diff options
Diffstat (limited to 'kaffeine/src/input/dvb/dvbcam.cpp')
-rw-r--r-- | kaffeine/src/input/dvb/dvbcam.cpp | 1252 |
1 files changed, 619 insertions, 633 deletions
diff --git a/kaffeine/src/input/dvb/dvbcam.cpp b/kaffeine/src/input/dvb/dvbcam.cpp index 1cb5b86..e525f6d 100644 --- a/kaffeine/src/input/dvb/dvbcam.cpp +++ b/kaffeine/src/input/dvb/dvbcam.cpp @@ -1,6 +1,7 @@ /* * dvbcam.cpp * + * Copyright (C) 2008 Christophe Thommeret <hftom@free.fr> * Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com> * * code based on ca_zap (LGPL) @@ -29,173 +30,48 @@ #include <sys/poll.h> #include <linux/dvb/ca.h> -#include <libdvbapi/dvbca.h> -#include <libdvbapi/dvbdemux.h> -#include <libdvben50221/en50221_app_ai.h> -#include <libdvben50221/en50221_app_ca.h> -#include <libdvben50221/en50221_app_rm.h> -#include <libdvben50221/en50221_app_tags.h> -#include <libdvben50221/en50221_session.h> -#include <libucsi/mpeg/section.h> - +#include <qapplication.h> #include <qthread.h> #include <qstring.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qtextbrowser.h> +#include <qlineedit.h> +#include <qpushbutton.h> #include "dvbcam.h" -class DvbCamCamHandler -{ -public: - virtual ~DvbCamCamHandler(); - - bool init(); - - virtual void poll() = 0; - virtual bool registerCam(int ca_fd, uint8_t slot) = 0; - - bool sendPmt(char *pmt_buffer, int size); - -protected: - DvbCamCamHandler(); - - static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids); - - virtual bool sub_init() = 0; - - void *AiResource; - void *CaResource; - en50221_app_send_functions SendFuncs; - - volatile int SessionNumber; -}; - -class DvbCamCamThread : protected QThread -{ -public: - DvbCamCamThread(int adapter, int ca_device, int ci_type); - ~DvbCamCamThread(); - - void start(); - void stop(); - void wait(); - - bool processPmt(int demux_fd); - -private: - void run(); - - int Adapter; - int CaDevice; - int ciType; - - DvbCamCamHandler *CamHandler; - - char PmtBuffer[4096]; // we imply that processPmt is only once called - - volatile int PmtSize; // PmtSize <= 0 means PmtBuffer invalid - volatile bool Stopped; -}; - -class DvbCamPmtThread : protected QThread -{ -public: - DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id); - ~DvbCamPmtThread(); - - void start(); - void stop(); - void wait(); - -private: - int createSectionFilter(uint16_t pid, uint8_t table_id); - int processPat(int demux_fd); - void run(); +#define TIMER_EVENT_MMI_OPEN 500 +#define TIMER_EVENT_MMI_CLOSE 501 +#define TIMER_EVENT_CAM_READY 502 - DvbCamCamThread *CamThread; - int Adapter; - int DemuxDevice; - int ServiceId; - volatile bool Stopped; -}; -class DvbCamCamHandlerLLCI : public DvbCamCamHandler -{ -public: - DvbCamCamHandlerLLCI(); - ~DvbCamCamHandlerLLCI(); - -private: - struct SlResource - { - en50221_app_public_resource_id resid; - uint32_t binary_resource_id; - en50221_sl_resource_callback callback; - void *arg; - }; - - static int llci_rm_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number); - static int llci_rm_reply_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t resource_id_count, uint32_t *resource_ids); - static int llci_rm_changed_callback(void *arg, uint8_t slot_id, uint16_t session_number); - static int llci_lookup_callback(void *arg, uint8_t slot_id, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id); - static int llci_session_callback(void *arg, int reason, uint8_t slot_id, uint16_t session_number, uint32_t resource_id); - - void poll(); - bool registerCam(int ca_fd, uint8_t slot); - bool sub_init(); - - void *RmResource; - void *SessionLayer; - void *TransportLayer; - - SlResource Resources[3]; -}; - -class DvbCamCamHandlerHLCI : public DvbCamCamHandler -{ -public: - DvbCamCamHandlerHLCI(); - ~DvbCamCamHandlerHLCI(); - -private: - static int hlci_send_data(void *arg, uint16_t session_number, uint8_t *data, uint16_t data_length); - static int hlci_send_datav(void *arg, uint16_t session_number, iovec *vector, int iov_count); - - void poll(); - bool registerCam(int ca_fd, uint8_t slot); - bool sub_init(); -}; - -// class DvbCam - -DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type) +DvbCam::DvbCam(int adapter, int ca_device, int demux_device, int ci_type, int maxService) { Adapter = adapter; CaDevice = ca_device; DemuxDevice = demux_device; ciType = ci_type; + CamMaxService = maxService; + fprintf(stderr, "DvbCam: CamMaxService = %d\n", CamMaxService); - isRunning = false; + stdcam = NULL; + menuDialog = NULL; - CamThread = NULL; - PmtThread = NULL; - - // at that time, we do reset in cam_thread - /*if ( ciType!=CA_CI ) { //do not reset HLCI - int ca_fd = dvbca_open( Adapter, CaDevice ); - if(ca_fd < 0) // should not happen - fprintf(stderr, "CamThread: [error] opening ca device failed\n"); - else { - if(dvbca_reset(ca_fd, 0)) - fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); - close(ca_fd); - } - }*/ + sidList.setAutoDelete( true ); + + isRunning = true; + start(); } DvbCam::~DvbCam() { - stop(); + isRunning = false; + wait(); + sidMutex.lock(); + sidList.clear(); + sidMutex.unlock(); } int DvbCam::probe( int adapter, int ca_device ) @@ -251,676 +127,786 @@ int DvbCam::probe( int adapter, int ca_device ) return -1; } -void DvbCam::restart(int service_id) +bool DvbCam::canPlay( ChannelDesc *chan ) { - stop(); - - isRunning = true; - sid = service_id; - - CamThread = new DvbCamCamThread(Adapter, CaDevice, ciType); - CamThread->start(); + int i, n=0; - PmtThread = new DvbCamPmtThread(CamThread, Adapter, DemuxDevice, service_id); - PmtThread->start(); -} - -void DvbCam::stop() -{ - if(PmtThread != NULL) { - PmtThread->stop(); - } - if(CamThread != NULL) { - CamThread->stop(); - } - if(PmtThread != NULL) { - PmtThread->wait(); - delete PmtThread; - PmtThread = NULL; - } - if(CamThread != NULL) { - CamThread->wait(); - delete CamThread; // be careful about deletion: PmtThread uses CamThread internally - CamThread = NULL; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getState()<CamService::Remove ) + n++; + if ( sidList.at(i)->getChannel().name==chan->name ) + return true; } - isRunning = false; -} - -// class DvbCamCamThread - -DvbCamCamThread::DvbCamCamThread(int adapter, int ca_device, int ci_type) -{ - Adapter = adapter; - CaDevice = ca_device; - ciType = ci_type; - - CamHandler = NULL; -} - -DvbCamCamThread::~DvbCamCamThread() -{ - wait(); // should never be necessary + return ( n<CamMaxService ); } -void DvbCamCamThread::start() +void DvbCam::startService( ChannelDesc *chan ) { - PmtSize = 0; - Stopped = false; - QThread::start(); -} - -void DvbCamCamThread::stop() -{ - Stopped = true; + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getChannel().name==chan->name ) { + sidList.at(i)->restart(); + return; + } + } + sidList.append( new CamService( Adapter, DemuxDevice, chan, CamMaxService ) ); } -void DvbCamCamThread::wait() +void DvbCam::stopService( ChannelDesc *chan ) { - QThread::wait(); + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getChannel().name==chan->name ) { + sidList.at(i)->setState( CamService::Remove ); + return; + } + } } -bool DvbCamCamThread::processPmt(int demux_fd) +void DvbCam::resendPmts() { - // read section - char si_buf[4096]; - int size = read(demux_fd, si_buf, sizeof(si_buf)); - if(size <= 0) { - return false; - } - - // parse section - section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); - if(parsed_section == NULL) { - return false; - } - - // parse section_ext - section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on - if(parsed_section_ext == NULL) { - return false; - } - - // parse pmt - mpeg_pmt_section *parsed_pmt = mpeg_pmt_section_codec(parsed_section_ext); - if(parsed_pmt == NULL) { - return false; - } - - // translate it into a cam pmt - PmtSize = en50221_ca_format_pmt(parsed_pmt, reinterpret_cast<unsigned char *> (PmtBuffer), sizeof(PmtBuffer), 0, CA_LIST_MANAGEMENT_ONLY, CA_PMT_CMD_ID_OK_DESCRAMBLING); - if(PmtSize <= 0) { - return false; + int i; + QMutexLocker locker( &sidMutex ); + for ( i=0; i<sidList.count(); ++i ) { + if ( sidList.at(i)->getState()==CamService::Added ) { + sidList.at(i)->setState( CamService::Ready ); + } } - - // the DvbCamCamThread will send it to the cam - return true; } -void DvbCamCamThread::run() +void DvbCam::run() { + int i, reset_loop, query_loop, state_loop; + bool cam_ready = false; + fprintf(stderr, "CamThread: started\n"); int ca_fd = dvbca_open(Adapter, CaDevice); - if(ca_fd < 0) { - fprintf(stderr, "CamThread: [error] opening ca device failed\n"); + if ( ca_fd<0 ) { + fprintf( stderr, "CamThread: [error] opening ca device failed\n" ); return; } - fprintf(stderr, "CamThread: just using the first cam slot\n"); + //fprintf(stderr, "CamThread: just using the first cam slot\n"); - if ( ciType!=CA_CI ) { // do not reset HLCI - if(dvbca_reset(ca_fd, 0)) { - fprintf(stderr, "CamThread: [error] resetting cam slot failed\n"); - close(ca_fd); - return; + reset_loop=0; + while ( isRunning && reset_loop++<6 && !cam_ready ) { + if ( ciType!=CA_CI ) { // do not reset HLCI + if ( dvbca_reset(ca_fd, 0) ) { + fprintf( stderr, "CamThread: [error] resetting cam slot failed\n" ); + //close( ca_fd ); + //ca_fd = -1; + //return; + usleep(1000000); + continue; + } + fprintf( stderr, "CamThread: reset cam slot\n" ); } - } - while(!Stopped) { - bool cam_ready = false; - switch(dvbca_get_cam_state(ca_fd, 0)) { - case DVBCA_CAMSTATE_MISSING: { - /*fprintf(stderr, "CamThread: [error] no cam detected\n"); - close(ca_fd); - return; */ // FIXME: find a more reliable solution - break; - } - case DVBCA_CAMSTATE_READY: { - fprintf(stderr, "CamThread: cam 0 is ready\n"); - cam_ready = true; - break; - } - case DVBCA_CAMSTATE_INITIALISING: { - if ( ciType==CA_CI ) { // workaround needed for hlci - fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n"); + state_loop=0; + query_loop=0; + while ( isRunning && state_loop++<30 ) { + switch( dvbca_get_cam_state(ca_fd, 0) ) { + case DVBCA_CAMSTATE_MISSING: { + //fprintf(stderr, "CamThread: [error] no cam detected\n"); + //close(ca_fd); + //return; // FIXME: find a more reliable solution + break; + } + case DVBCA_CAMSTATE_READY: { + fprintf( stderr, "CamThread: cam 0 is ready\n" ); cam_ready = true; + break; + } + case DVBCA_CAMSTATE_INITIALISING: { + fprintf( stderr, "CamThread: cam is initialising\n" ); + if ( ciType==CA_CI ) { // workaround needed for hlci + fprintf(stderr, "CamThread: cam 0 is ready [hlci workaround]\n"); + cam_ready = true; + } + break; + } + default: { + if ( ++query_loop>3 ) { + fprintf(stderr, "CamThread: [error] querying the cam state failed\n"); + close(ca_fd); + ca_fd = -1; + return; + } } - break; } - default: { - fprintf(stderr, "CamThread: [error] querying the cam state failed\n"); - close(ca_fd); - return; + if(cam_ready) { + break; } + usleep(100000); // 100 ms } - if(cam_ready) { - break; - } - usleep(100000); // 100 ms } - if(!Stopped) { + if ( isRunning ) { switch(dvbca_get_interface_type(ca_fd, 0)) { case DVBCA_INTERFACE_LINK: { fprintf(stderr, "CamThread: LLCI cam slot detected\n"); - CamHandler = new DvbCamCamHandlerLLCI(); break; } case DVBCA_INTERFACE_HLCI: { fprintf(stderr, "CamThread: HLCI cam slot detected\n"); - CamHandler = new DvbCamCamHandlerHLCI(); break; } default: { fprintf(stderr, "CamThread: [error] unknown cam slot type\n"); close(ca_fd); + ca_fd = -1; return; } } } - if(!Stopped) { - if(!CamHandler->init()) { - fprintf(stderr, "CamThread: [error] cam slot initialization failed\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); - return; - } - } + close(ca_fd); + ca_fd = -1; - if(!Stopped) { - if(!CamHandler->registerCam(ca_fd, 0)) { - fprintf(stderr, "CamThread: [error] registering cam 0 failed\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); + if ( isRunning ) { + if ( !init() ) { + fprintf(stderr, "CamThread: [error] cam slot initialisation failed\n"); return; } } + fprintf(stderr, "CamThread: cam slot initialised\n"); - while(!Stopped) { - CamHandler->poll(); - if(PmtSize > 0) { - if(CamHandler->sendPmt(PmtBuffer, PmtSize)) { - fprintf(stderr, "CamThread: pmt sent to cam\n"); - PmtSize = 0; + CamService *cs; + while ( isRunning ) { + if ( stdcam->stdcam->poll( stdcam->stdcam )!=EN50221_STDCAM_CAM_OK ) { + usleep( 100000 ); + continue; + } + sidMutex.lock(); + for ( i=0; i<sidList.count(); ++i ) { + cs = sidList.at(i); + if ( cs->getState()==CamService::Remove ) { + if ( sendPmt( cs->caPmt, cs->caPmtSize ) ) { + fprintf( stderr, "CamThread: %s removed from camlist\n", cs->getChannel().name.ascii() ); + sidList.remove( cs ); + --i; + } + else + fprintf( stderr, "CamThread: %s failed removing from camlist\n", cs->getChannel().name.ascii() ); + stdcam->stdcam->poll( stdcam->stdcam ); + usleep(100000); + } + else if ( cs->getState()==CamService::Destroy ) { + fprintf( stderr, "CamThread: %s service deleted\n", cs->getChannel().name.ascii() ); + sidList.remove( cs ); + --i; } } + for ( i=0; i<sidList.count(); ++i ) { + cs = sidList.at(i); + if ( cs->getState()==CamService::Ready ) { + if ( sendPmt( cs->caPmt, cs->caPmtSize ) ) { + cs->setState( CamService::Added ); + fprintf( stderr, "CamThread: %s pmt sent to cam\n", cs->getChannel().name.ascii() ); + } + else + fprintf( stderr, "CamThread: %s pmt failed sending to cam\n", cs->getChannel().name.ascii() ); + stdcam->stdcam->poll( stdcam->stdcam ); + usleep(100000); + } + } + sidMutex.unlock(); + usleep( 10000 ); //sleep a bit } fprintf(stderr, "CamThread: stopping requested\n"); - delete CamHandler; - CamHandler = NULL; - close(ca_fd); + if ( stdcam ) { + if (stdcam->stdcam->destroy) + stdcam->stdcam->destroy(stdcam->stdcam, 1); + en50221_sl_destroy( SessionLayer ); + en50221_tl_destroy( TransportLayer ); + delete stdcam; + } fprintf(stderr, "CamThread: stopped\n"); return; } -// class DvbCamPmtThread - -DvbCamPmtThread::DvbCamPmtThread(DvbCamCamThread *cam_thread, int adapter, int demux_device, int service_id) +bool DvbCam::init() { - CamThread = cam_thread; - Adapter = adapter; - DemuxDevice = demux_device; - ServiceId = service_id; + TransportLayer = en50221_tl_create(1, 16); + if ( TransportLayer==NULL ) { + fprintf(stderr, "Failed to create transport layer\n"); + return false; + } + SessionLayer = en50221_sl_create(TransportLayer, 16); + if ( SessionLayer==NULL ) { + fprintf(stderr, "Failed to create session layer\n"); + en50221_tl_destroy( TransportLayer ); + return false; + } + en50221_stdcam *sc = en50221_stdcam_create( Adapter, 0, TransportLayer, SessionLayer ); + if ( sc==NULL ) { + en50221_sl_destroy( SessionLayer ); + en50221_tl_destroy( TransportLayer ); + fprintf(stderr, "Failed to create stdcam\n"); + return false; + } + + stdcam = new StandardCam( sc, this ); + + // hook up the AI callbacks + if ( stdcam->stdcam->ai_resource ) { + en50221_app_ai_register_callback( stdcam->stdcam->ai_resource, aiCallback, stdcam ); + } + + // hook up the CA callbacks + if ( stdcam->stdcam->ca_resource ) { + en50221_app_ca_register_info_callback( stdcam->stdcam->ca_resource, infoCallback, stdcam ); + } + + // hook up the MMI callbacks + if ( stdcam->stdcam->mmi_resource ) { + en50221_app_mmi_register_close_callback( stdcam->stdcam->mmi_resource, mmi_close_callback, stdcam ); + en50221_app_mmi_register_display_control_callback( stdcam->stdcam->mmi_resource, mmi_display_control_callback, stdcam ); + en50221_app_mmi_register_enq_callback( stdcam->stdcam->mmi_resource, mmi_enq_callback, stdcam ); + en50221_app_mmi_register_menu_callback( stdcam->stdcam->mmi_resource, mmi_menu_callback, stdcam ); + en50221_app_mmi_register_list_callback( stdcam->stdcam->mmi_resource, mmi_menu_callback, stdcam ); + } else { + fprintf(stderr, "CAM Menus are not supported by this interface hardware\n"); + } + + return true; } -DvbCamPmtThread::~DvbCamPmtThread() +bool DvbCam::sendPmt( unsigned char *pmt_buffer, int size ) { - wait(); // should never be necessary + if ( !stdcam ) + return false; + if ( en50221_app_ca_pmt( stdcam->stdcam->ca_resource, stdcam->stdcam->ca_session_number, pmt_buffer, size) ) + return false; + + return true; } -void DvbCamPmtThread::start() +int DvbCam::infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids) { - Stopped = false; - QThread::start(); + StandardCam *std = (StandardCam*)arg; + (void)slot_id; + (void)session_number; + + fprintf(stderr, "CAM supports the following ca system ids:\n"); + uint32_t i; + for ( i=0; i<ca_id_count; i++ ) { + fprintf( stderr, " 0x%04x\n", ca_ids[i]); + } + + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_CAM_READY ) ); + + return 0; } -void DvbCamPmtThread::stop() +int DvbCam::aiCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t application_type, uint16_t application_manufacturer, uint16_t manufacturer_code, uint8_t menu_string_length, uint8_t *menu_string) { - Stopped = true; + StandardCam *std = (StandardCam*)arg; + (void)slot_id; + (void)session_number; + + fprintf(stderr, "CAM Application type: %02x\n", application_type); + std->dvbcam->setAppType( QString("0x%1").arg(application_type, 0, 16 ) ); + fprintf(stderr, "CAM Application manufacturer: %04x\n", application_manufacturer); + std->dvbcam->setAppManu( QString("0x%1").arg(application_manufacturer, 0, 16 ) ); + fprintf(stderr, "CAM Manufacturer code: %04x\n", manufacturer_code); + std->dvbcam->setManuCode( QString("0x%1").arg(manufacturer_code, 0, 16 ) ); + fprintf(stderr, "CAM Menu string: %.*s\n", menu_string_length, menu_string); + QString s = (const char*)menu_string; + s.truncate( menu_string_length ); + std->dvbcam->setMenuString( s ); + return 0; } -void DvbCamPmtThread::wait() +int DvbCam::mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay) { - QThread::wait(); + fprintf( stderr,"mmi_close_callback, delay=%d\n",delay); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; + (void) cmd_id; + (void) delay; + + // note: not entirely correct as its supposed to delay if asked + std->mmi_state = MMI_STATE_CLOSED; + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_MMI_CLOSE ) ); + return 0; } -int DvbCamPmtThread::createSectionFilter(uint16_t pid, uint8_t table_id) +int DvbCam::mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t mmi_mode) { - // open the demuxer - int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0); - if(demux_fd < 0) { - return -1; + fprintf( stderr,"mmi_display_control_callback\n"); + struct en50221_app_mmi_display_reply_details reply; + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + + // don't support any commands but set mode + if ( cmd_id!=MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE ) { + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID, &reply ); + return 0; } - // create a section filter - uint8_t filter[18] = {table_id}; - uint8_t mask[18] = {0xff}; - if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on - close(demux_fd); - return -1; + // we only support high level mode + if ( mmi_mode!=MMI_MODE_HIGH_LEVEL ) { + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE, &reply ); + return 0; } - return demux_fd; + // ack the high level open + reply.u.mode_ack.mmi_mode = mmi_mode; + en50221_app_mmi_display_reply( std->stdcam->mmi_resource, session_number, MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK, &reply ); + std->mmi_state = MMI_STATE_OPEN; + return 0; } -int DvbCamPmtThread::processPat(int demux_fd) +int DvbCam::mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t blind_answer, uint8_t expected_answer_length, + uint8_t *text, uint32_t text_size) { - // read section - char si_buf[4096]; - int size = read(demux_fd, si_buf, sizeof(si_buf)); - if(size < 0) { - return -1; - } + fprintf( stderr,"mmi_enq_callback\n"); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; - // parse section - section *parsed_section = section_codec(reinterpret_cast<unsigned char *> (si_buf), size); - if(parsed_section == NULL) { - return -1; - } + QString s; - // parse section_ext - section_ext *parsed_section_ext = section_ext_decode(parsed_section, 1); // crc check on - if(parsed_section_ext == NULL) { - return -1; - } + QMutexLocker locker( &std->mutex ); - // parse pat - mpeg_pat_section *parsed_pat = mpeg_pat_section_codec(parsed_section_ext); - if(parsed_pat == NULL) { - return -1; - } + std->menuList.clear(); + fprintf(stderr, "%.*s: ", text_size, text); + s = (const char*)text; + s.truncate( text_size ); + std->menuList.append( s ); + fflush(stdout); - // try and find the requested program - mpeg_pat_program *cur_program; - mpeg_pat_section_programs_for_each(parsed_pat, cur_program) { - if(cur_program->program_number == ServiceId) { - return cur_program->pid; - } - } + std->mmi_enq_blind = blind_answer; + std->mmi_enq_length = expected_answer_length; + std->mmi_state = MMI_STATE_ENQ; + std->menuType = MMI_MENU; - fprintf(stderr, "PmtThread: [warning] the requested service id couldn't be found\n"); - - return -1; + return 0; } -void DvbCamPmtThread::run() +int DvbCam::mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number, struct en50221_app_mmi_text *title, + struct en50221_app_mmi_text *sub_title, struct en50221_app_mmi_text *bottom, uint32_t item_count, + struct en50221_app_mmi_text *items, uint32_t item_raw_length, uint8_t *items_raw) { - fprintf(stderr, "PmtThread: started\n"); + fprintf( stderr,"mmi_menu_callback, session=%d\n",session_number); + StandardCam *std = (StandardCam*)arg; + (void) slot_id; + (void) session_number; + (void) item_raw_length; + (void) items_raw; - int demux_fd = createSectionFilter(TRANSPORT_PAT_PID, stag_mpeg_program_association); - if(demux_fd < 0) { - fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); - return; - } + QString s; - pollfd poll_desc; - poll_desc.fd = demux_fd; - poll_desc.events = POLLIN | POLLPRI; - while(!Stopped) { - int ret = poll(&poll_desc, 1, 100); // 100 ms - if(ret < 0) { - fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); - close(demux_fd); - return; - } - if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { - int processed_pat = processPat(demux_fd); - if(processed_pat >= 0) { - close(demux_fd); - demux_fd = createSectionFilter(processed_pat, stag_mpeg_program_map); - if(demux_fd < 0) { - fprintf(stderr, "PmtThread: [error] opening demux device failed\n"); - return; - } - poll_desc.fd = demux_fd; - break; - } - } - } + QMutexLocker locker( &std->mutex ); + std->menuList.clear(); - while(!Stopped) { - int ret = poll(&poll_desc, 1, 100); // 100 ms - if(ret < 0) { - fprintf(stderr, "PmtThread: [error] polling demux device failed\n"); - close(demux_fd); - return; - } - if((ret > 0) && (poll_desc.revents != 0) && ((poll_desc.revents & ~(POLLIN | POLLPRI)) == 0)) { - if(CamThread->processPmt(demux_fd)) { - fprintf(stderr, "PmtThread: new pmt received\n"); - close(demux_fd); - fprintf(stderr, "PmtThread: stopped\n"); - return; - } - } + fprintf(stderr, "------------------------------\n"); + + if (title->text_length) { + fprintf(stderr, "%.*s\n", title->text_length, title->text); + s = (const char*)title->text; + s.truncate( title->text_length ); + std->menuList.append( s ); + } + if (sub_title->text_length) { + fprintf(stderr, "%.*s\n", sub_title->text_length, sub_title->text); + s = (const char*)sub_title->text; + s.truncate( sub_title->text_length ); + std->menuList.append( s ); } - fprintf(stderr, "PmtThread: stopping requested\n"); + uint32_t i; + fprintf(stderr, "0. Quit menu\n"); + std->menuList.append( "0. Quit menu" ); + for(i=0; i< item_count; i++) { + fprintf(stderr, "%i. %.*s\n", i+1, items[i].text_length, items[i].text); + s = (const char*)items[i].text; + s.truncate( items[i].text_length ); + std->menuList.append( QString("%1. %2").arg(i+1).arg(s) ); - close(demux_fd); + } - fprintf(stderr, "PmtThread: stopped\n"); - return; -} + if (bottom->text_length) { + fprintf(stderr, "%.*s\n", bottom->text_length, bottom->text); + s = (const char*)bottom->text; + s.truncate( bottom->text_length ); + std->menuList.append( s ); + } + fflush(stdout); -// class DvbCamCamHandler + std->mmi_state = MMI_STATE_MENU; + std->menuType = MMI_MENU; -DvbCamCamHandler::DvbCamCamHandler() -{ - AiResource = NULL; - CaResource = NULL; + QApplication::postEvent( std->dvbcam, new QTimerEvent(TIMER_EVENT_MMI_OPEN ) ); - SessionNumber = -1; + return 0; } -DvbCamCamHandler::~DvbCamCamHandler() +void DvbCam::timerEvent( QTimerEvent *e ) { - if(CaResource != NULL) { - en50221_app_ca_destroy(CaResource); - CaResource = NULL; - } - if(AiResource != NULL) { - en50221_app_ai_destroy(AiResource); - AiResource = NULL; + switch ( e->timerId() ) { + case TIMER_EVENT_MMI_OPEN: + showMMI(); + break; + case TIMER_EVENT_MMI_CLOSE: + closeMMI(); + break; + case TIMER_EVENT_CAM_READY: + resendPmts(); + break; } } -bool DvbCamCamHandler::init() +void DvbCam::showMMI() { - AiResource = en50221_app_ai_create(&SendFuncs); - CaResource = en50221_app_ca_create(&SendFuncs); - - if(CaResource != NULL) { - en50221_app_ca_register_info_callback(CaResource, infoCallback, this); + if ( !menuDialog && stdcam ) { + menuDialog = new MCamMenuDialog( stdcam ); + connect( menuDialog, SIGNAL(enteredResponse(QString)), this, SLOT(mmiResponse(QString)) ); + menuDialog->exec(); + closeMMI(); } - - return sub_init(); } -bool DvbCamCamHandler::sendPmt(char *pmt_buffer, int size) +void DvbCam::closeMMI() { - if((CaResource != NULL) && (SessionNumber >= 0)) { - if(!en50221_app_ca_pmt(CaResource, SessionNumber, reinterpret_cast<unsigned char *> (pmt_buffer), size)) { - return true; + if ( menuDialog ) { + delete menuDialog; + menuDialog = 0; + if ( stdcam && stdcam->stdcam->mmi_resource ) { + en50221_app_mmi_close( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_CLOSE_MMI_CMD_ID_IMMEDIATE, 0 ); + stdcam->mmi_state = MMI_STATE_CLOSED; } } - - return false; } -int DvbCamCamHandler::infoCallback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*ca_id_count*/, uint16_t */*ca_ids*/) +int DvbCam::showCamDialog() { - (static_cast<DvbCamCamHandler *> (arg))->SessionNumber = session_number; - return 0; -} -// class DvbCamCamHandlerLLCI - -#define MAX_CARDS 1 -#define MAX_TC 16 -#define MAX_SESSIONS 16 + CamDialog dlg; + dlg.maxServiceSpin->setValue( getCamMaxService() ); + dlg.appTypeLab->setText( getAppType() ); + dlg.appManuLab->setText( getAppManu() ); + dlg.manuCodeLab->setText( getManuCode() ); + dlg.menuStringLab->setText( getMenuString() ); + connect( dlg.camMenuBtn, SIGNAL(clicked()), this, SLOT(enterMenu()) ); + dlg.exec(); + CamMaxService = dlg.maxServiceSpin->value(); + return CamMaxService; +} -DvbCamCamHandlerLLCI::DvbCamCamHandlerLLCI() +void DvbCam::enterMenu() { - RmResource = NULL; - SessionLayer = NULL; - TransportLayer = NULL; + if ( stdcam && stdcam->stdcam->ai_resource ) + en50221_app_ai_entermenu( stdcam->stdcam->ai_resource, stdcam->stdcam->ai_session_number ); } -DvbCamCamHandlerLLCI::~DvbCamCamHandlerLLCI() +void DvbCam::mmiResponse( QString s ) { - if(SessionLayer != NULL) { - en50221_sl_destroy(SessionLayer); - SessionLayer = NULL; - } - if(TransportLayer != NULL) { - en50221_tl_destroy(TransportLayer); - TransportLayer = NULL; - } - if(RmResource != NULL) { - en50221_app_rm_destroy(RmResource); - RmResource = NULL; + QString res = s.stripWhiteSpace(); + + switch( stdcam->mmi_state ) { + case MMI_STATE_CLOSED: + case MMI_STATE_OPEN: { + en50221_app_ai_entermenu(stdcam->stdcam->ai_resource, stdcam->stdcam->ai_session_number); + fprintf(stderr,"en50221_app_ai_entermenu 2\n"); + break; + } + case MMI_STATE_ENQ: { + if ( res.isEmpty() ) { + en50221_app_mmi_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_ANSW_ID_CANCEL, NULL, 0); + } + else { + en50221_app_mmi_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, MMI_ANSW_ID_ANSWER, (uint8_t*)res.ascii(), res.length() ); + } + stdcam->mmi_state = MMI_STATE_OPEN; + break; + } + case MMI_STATE_MENU: { + en50221_app_mmi_menu_answ( stdcam->stdcam->mmi_resource, stdcam->stdcam->mmi_session_number, res.toInt() ); + stdcam->mmi_state = MMI_STATE_OPEN; + break; + } } } -int DvbCamCamHandlerLLCI::llci_rm_enq_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) + + + +MCamMenuDialog::MCamMenuDialog( StandardCam *sc ) { - uint32_t resource_ids[] = {EN50221_APP_RM_RESOURCEID, EN50221_APP_AI_RESOURCEID, EN50221_APP_CA_RESOURCEID}; - en50221_app_rm_reply(arg, session_number, sizeof(resource_ids) / 4, resource_ids); - return 0; + stdcam = sc; + connect( inputLine, SIGNAL(returnPressed()), this, SLOT(validateClicked()) ); + connect( &readTimer, SIGNAL(timeout()), this, SLOT(setMenu()) ); + readTimer.start( 500 ); } -int DvbCamCamHandlerLLCI::llci_rm_reply_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number, uint32_t /*resource_id_count*/, uint32_t */*resource_ids*/) +void MCamMenuDialog::setMenu() { - en50221_app_rm_changed(arg, session_number); - return 0; + if ( !stdcam ) + return; + QMutexLocker locker( &stdcam->mutex ); + if ( stdcam->menuType==MMI_MENU ) + menuText->setText( stdcam->menuList.join("\n") ); } -int DvbCamCamHandlerLLCI::llci_rm_changed_callback(void *arg, uint8_t /*slot_id*/, uint16_t session_number) +void MCamMenuDialog::validateClicked() { - en50221_app_rm_enq(arg, session_number); - return 0; + emit enteredResponse( inputLine->text() ); + inputLine->clear(); } -int DvbCamCamHandlerLLCI::llci_lookup_callback(void *arg, uint8_t /*slot_id*/, uint32_t requested_resource_id, en50221_sl_resource_callback *callback_out, void **arg_out, uint32_t *connected_resource_id) + + + + +// class CamService +CamService::CamService( int adapter, int demux_device, ChannelDesc *chan, int maxService ) { - // decode the resource id - en50221_app_public_resource_id resid; - if(!en50221_app_decode_public_resource_id(&resid, requested_resource_id)) { - return -1; - } + Adapter = adapter; + DemuxDevice = demux_device; + CamMaxService = maxService; + channel = *chan; + parsedPmt = NULL; + state = NotReady; + isRunning = true; + start(); +} - // try and find an instance of the resource - const SlResource *Resources = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources; - int i; - for(i = 0; i < 3; ++i) { - if((resid.resource_class == Resources[i].resid.resource_class) && (resid.resource_type == Resources[i].resid.resource_type)) { - *callback_out = Resources[i].callback; - *arg_out = Resources[i].arg; - *connected_resource_id = Resources[i].binary_resource_id; - return 0; - } - } - return -1; +CamService::~CamService() +{ + stop(); } -int DvbCamCamHandlerLLCI::llci_session_callback(void *arg, int reason, uint8_t /*slot_id*/, uint16_t session_number, uint32_t resource_id) +void CamService::restart() { - if(reason == S_SCALLBACK_REASON_CAMCONNECTED) { - if(resource_id == EN50221_APP_RM_RESOURCEID) { - void *RmResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[0].arg; - en50221_app_rm_enq(RmResource, session_number); - } - else if(resource_id == EN50221_APP_AI_RESOURCEID) { - void *AiResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[1].arg; - en50221_app_ai_enquiry(AiResource, session_number); - } - else if(resource_id == EN50221_APP_CA_RESOURCEID) { - void *CaResource = (static_cast<DvbCamCamHandlerLLCI *> (arg))->Resources[2].arg; - en50221_app_ca_info_enq(CaResource, session_number); - } - } - return 0; + setState( NotReady ); } -void DvbCamCamHandlerLLCI::poll() +void CamService::stop() { - if(en50221_tl_poll(TransportLayer)) { - fprintf(stderr, "CamThread: [warning] polling the stack failed\n"); - usleep(10000); // wait 10 ms to not block - } + isRunning = false; + wait(); } -bool DvbCamCamHandlerLLCI::registerCam(int ca_fd, uint8_t slot) +int CamService::createSectionFilter(uint16_t pid, uint8_t table_id) { - // register the slot - int slot_id = en50221_tl_register_slot(TransportLayer, ca_fd, slot, 1000, 100); - if(slot_id < 0) { - return false; + // open the demuxer + int demux_fd = dvbdemux_open_demux(Adapter, DemuxDevice, 0); + if(demux_fd < 0) { + return -1; } - // create a new connection on the slot - if(en50221_tl_new_tc(TransportLayer, slot_id) < 0) { - return false; + // create a section filter + uint8_t filter[18] = {table_id}; + uint8_t mask[18] = {0xff}; + if(dvbdemux_set_section_filter(demux_fd, pid, filter, mask, 1, 1)) { // crc check on + close(demux_fd); + return -1; } - return true; + return demux_fd; } -bool DvbCamCamHandlerLLCI::sub_init() +int CamService::processPat(int demux_fd) { - // create transport layer - TransportLayer = en50221_tl_create(MAX_CARDS, MAX_TC); - if(TransportLayer == NULL) { - return false; - } + // read section + unsigned char si_buf[4096]; + int size = read( demux_fd, si_buf, sizeof(si_buf) ); + if ( size<0 ) + return -1; - // create session layer - SessionLayer = en50221_sl_create(TransportLayer, MAX_SESSIONS); - if(SessionLayer == NULL) { - en50221_tl_destroy(TransportLayer); - TransportLayer = NULL; - return false; - } + // parse section + section *parsed_section = section_codec( si_buf, size ); + if ( parsed_section==NULL ) + return -1; - // create sendfuncs - SendFuncs.arg = SessionLayer; - SendFuncs.send_data = en50221_sl_send_data; - SendFuncs.send_datav = en50221_sl_send_datav; - - // create the resource manager resource - RmResource = en50221_app_rm_create(&SendFuncs); - en50221_app_decode_public_resource_id(&Resources[0].resid, EN50221_APP_RM_RESOURCEID); - Resources[0].binary_resource_id = EN50221_APP_RM_RESOURCEID; - Resources[0].callback = en50221_app_rm_message; - Resources[0].arg = RmResource; - en50221_app_rm_register_enq_callback(RmResource, llci_rm_enq_callback, RmResource); - en50221_app_rm_register_reply_callback(RmResource, llci_rm_reply_callback, RmResource); - en50221_app_rm_register_changed_callback(RmResource, llci_rm_changed_callback, RmResource); - - // integrate the application information resource - en50221_app_decode_public_resource_id(&Resources[1].resid, EN50221_APP_AI_RESOURCEID); - Resources[1].binary_resource_id = EN50221_APP_AI_RESOURCEID; - Resources[1].callback = en50221_app_ai_message; - Resources[1].arg = AiResource; - - // integrate the ca resource - en50221_app_decode_public_resource_id(&Resources[2].resid, EN50221_APP_CA_RESOURCEID); - Resources[2].binary_resource_id = EN50221_APP_CA_RESOURCEID; - Resources[2].callback = en50221_app_ca_message; - Resources[2].arg = CaResource; - - // register session layer callbacks - en50221_sl_register_lookup_callback(SessionLayer, llci_lookup_callback, this); - en50221_sl_register_session_callback(SessionLayer, llci_session_callback, this); + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode( parsed_section, 1 ); // crc check on + if ( parsed_section_ext==NULL ) + return -1; - return true; -} + // parse pat + mpeg_pat_section *parsed_pat = mpeg_pat_section_codec( parsed_section_ext ); + if ( parsed_pat==NULL ) + return -1; -// class DvbCamCamHandlerHLCI + // try and find the requested program + mpeg_pat_program *cur_program; + mpeg_pat_section_programs_for_each( parsed_pat, cur_program ) { + if ( cur_program->program_number==channel.sid ) + return cur_program->pid; + } -DvbCamCamHandlerHLCI::DvbCamCamHandlerHLCI() -{ -} + fprintf( stderr, "CamService (%s): [warning] channel couldn't be found in PAT\n", channel.name.ascii() ); -DvbCamCamHandlerHLCI::~DvbCamCamHandlerHLCI() -{ + return -1; } -int DvbCamCamHandlerHLCI::hlci_send_data(void *arg, uint16_t /*session_number*/, uint8_t *data, uint16_t data_length) +int CamService::processPmt( int demux_fd ) { - return dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), data, data_length); -} + // read section + memset( pmtBuffer, 0, sizeof(pmtBuffer) ); + int size = read( demux_fd, pmtBuffer, sizeof(pmtBuffer) ); + if ( size<=0 ) + return -1; -int DvbCamCamHandlerHLCI::hlci_send_datav(void *arg, uint16_t /*session_number*/, iovec *vector, int iov_count) -{ - // calculate the total length of the data to send - uint32_t data_size = 0; - for(int i = 0; i < iov_count; ++i) { - data_size += vector[i].iov_len; - } + // parse section + section *parsed_section = section_codec( pmtBuffer, size ); + if ( parsed_section==NULL ) + return -1; - // allocate memory for it - uint8_t *buf = new uint8_t[data_size]; + // parse section_ext + section_ext *parsed_section_ext = section_ext_decode( parsed_section, 1 ); // crc check on + if ( parsed_section_ext==NULL ) + return -1; - // merge the iovecs - uint8_t *pos = buf; - for(int i = 0; i < iov_count; ++i) { - memcpy(pos, vector[i].iov_base, vector[i].iov_len); - pos += vector[i].iov_len; - } + // parse pmt + struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec( parsed_section_ext ); + if ( pmt==NULL ) + return -1; - // send it - int status = dvbca_hlci_write(static_cast<int> (reinterpret_cast<intptr_t> (arg)), buf, data_size); - delete buf; - return status; + parsedPmt = pmt; + return parsedPmt->head.version_number; } -void DvbCamCamHandlerHLCI::poll() +void CamService::setState( PmtState st ) { - // we do nothing here for the moment - usleep(100000); // 100 ms + QMutexLocker locker( &mutex ); + switch ( st ) { + case Ready: { + int listmgnt; + if ( CamMaxService==1 ) + listmgnt = CA_LIST_MANAGEMENT_ONLY; + else + listmgnt = CA_LIST_MANAGEMENT_ADD; + if ( state>Ready ) + listmgnt = CA_LIST_MANAGEMENT_UPDATE; + if ( setCaPmt( listmgnt, CA_PMT_CMD_ID_OK_DESCRAMBLING ) ) + state = st; + break; + } + case Remove: { + if ( state!=Added ) + state = Destroy; + else if ( setCaPmt( CA_LIST_MANAGEMENT_UPDATE, CA_PMT_CMD_ID_NOT_SELECTED ) ) + state = st; + break; + } + default: { + state = st; + } + } } -bool DvbCamCamHandlerHLCI::registerCam(int ca_fd, uint8_t /*slot*/) +int CamService::getState() { - SendFuncs.arg = reinterpret_cast<void *> (ca_fd); - - // get application information - if(en50221_app_ai_enquiry(AiResource, 0)) { - fprintf(stderr, "CamThread: [DEBUG #1]\n"); - return false; - } - - uint8_t buf[256]; - int size = dvbca_hlci_read(ca_fd, TAG_APP_INFO, buf, sizeof(buf)); - if(size <= 0) { - fprintf(stderr, "CamThread: [DEBUG #2]\n"); - return false; - } + QMutexLocker locker( &mutex ); + return state; +} - if(en50221_app_ai_message(AiResource, 0, 0, EN50221_APP_AI_RESOURCEID, buf, size)) { - fprintf(stderr, "CamThread: [DEBUG #3]\n"); +bool CamService::setCaPmt( int list_management, int cmd_id ) +{ + if ( !parsedPmt ) return false; - } - // FIXME: try to change this soon - buf[0] = TAG_CA_INFO >> 16; - buf[1] = TAG_CA_INFO >> 8; - buf[2] = TAG_CA_INFO; - buf[3] = 0; - if(en50221_app_ca_message(CaResource, 0, 0, EN50221_APP_CA_RESOURCEID, buf, 4)) { - fprintf(stderr, "CamThread: [DEBUG #4]\n"); + caPmtSize = en50221_ca_format_pmt( parsedPmt, caPmt, sizeof(caPmt), 0, list_management, cmd_id ); + if ( caPmtSize<=0 ) return false; - } - - fprintf(stderr, "CamThread: [DEBUG #5]\n"); return true; } -bool DvbCamCamHandlerHLCI::sub_init() +void CamService::run() { - // create sendfuncs - SendFuncs.arg = NULL; - SendFuncs.send_data = hlci_send_data; - SendFuncs.send_datav = hlci_send_datav; + int i, pmtVersion=-1; + int demux_fd=-1; - return true; + fprintf( stderr, "CamService (%s): started\n", channel.name.ascii() ); + + while ( isRunning ) { +loopLabel: + demux_fd = createSectionFilter( TRANSPORT_PAT_PID, stag_mpeg_program_association ); + if ( demux_fd<0 ) { + fprintf( stderr, "CamService (%s): [error] opening demux device failed\n", channel.name.ascii() ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + + pollfd poll_desc; + poll_desc.fd = demux_fd; + poll_desc.events = POLLIN | POLLPRI; + while ( isRunning ) { + int ret = poll( &poll_desc, 1, 1000 ); + if ( ret<0 ) { + fprintf( stderr, "CamService (%s): [error] polling demux device failed\n", channel.name.ascii() ); + close( demux_fd ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + if ( ret>0 ) { + int processed_pat = processPat( demux_fd ); + if ( processed_pat>=0 ) { + close( demux_fd ); + demux_fd = -1; + demux_fd = createSectionFilter( processed_pat, stag_mpeg_program_map ); + if ( demux_fd<0 ) { + fprintf( stderr, "CamService (%s): [error] opening demux device failed\n", channel.name.ascii() ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + poll_desc.fd = demux_fd; + break; + } + else + usleep( 10000 ); + } + else + usleep( 10000 ); + } + + while ( isRunning ) { + int ret = poll( &poll_desc, 1, 1000 ); + if ( ret<0 ) { + fprintf( stderr, "CamService (%s): [error] polling demux device failed\n", channel.name.ascii() ); + close( demux_fd ); + demux_fd = -1; + usleep( 100000 ); + goto loopLabel; + } + if ( ret>0 ) { + //fprintf( stderr, "CamService (%s): parsing pmt\n", channel.name.ascii() ); + i = processPmt( demux_fd ); + if ( i==-1 ) + usleep( 10000 ); + else { + if ( i!=pmtVersion || getState()<Ready ) { + fprintf( stderr, "CamService (%s): new pmt received\n", channel.name.ascii() ); + setState( Ready ); + pmtVersion = i; + } + i = 200; + while ( i-- && isRunning ) + usleep( 10000 ); + } + } + else + usleep( 10000 ); + } + } + + if ( demux_fd != -1 ) + close( demux_fd ); + fprintf( stderr, "CamService (%s): stopped\n", channel.name.ascii() ); } |