work on ci support
authorAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 22 Nov 2005 20:03:07 +0000 (20:03 +0000)
committerAndreas Monzner <andreas.monzner@multimedia-labs.de>
Tue, 22 Nov 2005 20:03:07 +0000 (20:03 +0000)
please update the libdvbsi++ to CVSDATE >= 20051119

lib/dvb/pmt.cpp
lib/dvb/pmt.h
lib/dvb_ci/dvbci.cpp
lib/dvb_ci/dvbci.h
lib/dvb_ci/dvbci_camgr.cpp
lib/dvb_ci/dvbci_camgr.h

index c886c39a378767313986779fd41ead2d95409dd2..e77c097d1a7b27075f20c3f30a49dc9d2037d2fd 100644 (file)
@@ -3,6 +3,7 @@
 #include <lib/dvb/specs.h>
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/metaparser.h>
+#include <lib/dvb_ci/dvbci.h>
 #include <dvbsi++/ca_program_map_section.h>
 
 eDVBServicePMTHandler::eDVBServicePMTHandler(int record)
@@ -12,6 +13,7 @@ eDVBServicePMTHandler::eDVBServicePMTHandler(int record)
        eDVBResourceManager::getInstance(m_resourceManager);
        CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
        CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
+       eDVBCIInterfaces::getInstance()->addPMTHandler(this);
        eDebug("new PMT handler record: %d", m_record);
 }
 
@@ -27,6 +29,7 @@ eDVBServicePMTHandler::~eDVBServicePMTHandler()
                m_PMT.getCurrent(ptr);
                eDVBCAService::unregister_service(m_reference, demux_num, ptr);
        }
+       eDVBCIInterfaces::getInstance()->removePMTHandler(this);
 }
 
 void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
@@ -69,11 +72,15 @@ void eDVBServicePMTHandler::PMTready(int error)
        else
        {
                serviceEvent(eventNewProgramInfo);
-               if (!m_pvr_channel && !m_ca_servicePtr)   // don't send campmt to camd.socket for playbacked services
+               if (!m_pvr_channel)
                {
-                       uint8_t demux_num;
-                       m_demux->getCADemuxID(demux_num);
-                       eDVBCAService::register_service(m_reference, demux_num, m_ca_servicePtr);
+                       eDVBCIInterfaces::getInstance()->gotPMT(this);
+                       if(!m_ca_servicePtr)   // don't send campmt to camd.socket for playbacked services
+                       {
+                               uint8_t demux_num;
+                               m_demux->getCADemuxID(demux_num);
+                               eDVBCAService::register_service(m_reference, demux_num, m_ca_servicePtr);
+                       }
                }
                if (m_ca_servicePtr)
                {
@@ -200,6 +207,15 @@ int eDVBServicePMTHandler::getProgramInfo(struct program &program)
        return -1;
 }
 
+int eDVBServicePMTHandler::getChannel(eUsePtr<iDVBChannel> &channel)
+{
+       channel = m_channel;
+       if (channel)
+               return 0;
+       else
+               return -1;
+}
+
 int eDVBServicePMTHandler::getDemux(ePtr<iDVBDemux> &demux)
 {
        demux = m_demux;
index bf83a70a8975cd1197a150bfa4d850d9c4c6e11d..a23abf1e3142e63cde68959f610a055f3e6d7df8 100644 (file)
@@ -108,8 +108,11 @@ public:
        int getProgramInfo(struct program &program);
        int getDemux(ePtr<iDVBDemux> &demux);
        int getPVRChannel(ePtr<iDVBPVRChannel> &pvr_channel);
-       
-       int tune(eServiceReferenceDVB &ref);    
+       int getService(eServiceReferenceDVB &service) { service = m_reference; return 0; }
+       int getPMT(ePtr<eTable<ProgramMapSection> > &ptr) { return m_PMT.getCurrent(ptr); }
+       int getChannel(eUsePtr<iDVBChannel> &channel);
+
+       int tune(eServiceReferenceDVB &ref);
 };
 
 #endif
index 18e66620c06939fccde49b8f9b10966e46a3c4c1..82d3349d7d46f2f658f898e0de20b6a90371a32e 100644 (file)
@@ -6,13 +6,16 @@
 #include <lib/base/ebase.h>
 
 #include <lib/base/eerror.h>
+#include <lib/dvb/pmt.h>
 #include <lib/dvb_ci/dvbci.h>
 #include <lib/dvb_ci/dvbci_session.h>
-
+#include <lib/dvb_ci/dvbci_camgr.h>
 #include <lib/dvb_ci/dvbci_ui.h>
 #include <lib/dvb_ci/dvbci_appmgr.h>
 #include <lib/dvb_ci/dvbci_mmi.h>
 
+#include <dvbsi++/ca_program_map_section.h>
+
 eDVBCIInterfaces *eDVBCIInterfaces::instance = 0;
 
 eDVBCIInterfaces::eDVBCIInterfaces()
@@ -123,6 +126,80 @@ int eDVBCIInterfaces::answerEnq(int slotid, int answer, char *value)
        return slot->answerEnq(answer, value);
 }
 
+void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
+{
+       CIPmtHandler new_handler(pmthandler);
+
+       eServiceReferenceDVB service;
+       pmthandler->getService(service);
+
+       PMTHandlerSet::iterator it = m_pmt_handlers.begin();
+       while (it != m_pmt_handlers.end())
+       {
+               eServiceReferenceDVB ref;
+               it->pmthandler->getService(ref);
+               if ( service == ref && it->usedby )
+                       new_handler.usedby = it->usedby;
+               break;
+       }
+       m_pmt_handlers.insert(new_handler);
+}
+
+void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
+{
+       PMTHandlerSet::iterator it=m_pmt_handlers.find(pmthandler);
+       if (it != m_pmt_handlers.end())
+       {
+               eDVBCISlot *slot = it->usedby;
+               eDVBServicePMTHandler *pmthandler = it->pmthandler;
+               m_pmt_handlers.erase(it);
+               if (slot)
+               {
+                       eServiceReferenceDVB removed_service;
+                       pmthandler->getService(removed_service);
+                       PMTHandlerSet::iterator it=m_pmt_handlers.begin();
+                       while (it != m_pmt_handlers.end())
+                       {
+                               eServiceReferenceDVB ref;
+                               it->pmthandler->getService(ref);
+                               if (ref == removed_service)
+                                       break;
+                               ++it;
+                       }
+                       if ( it == m_pmt_handlers.end() && slot->getPrevSentCAPMTVersion() != 0xFF  )
+                       {
+                               std::vector<uint16_t> caids;
+                               caids.push_back(0xFFFF);
+                               slot->sendCAPMT(pmthandler, caids);
+                       }
+               }
+       }
+}
+
+void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
+{
+       eDebug("[eDVBCIInterfaces] gotPMT");
+       PMTHandlerSet::iterator it=m_pmt_handlers.find(pmthandler);
+       eServiceReferenceDVB service;
+       if ( it != m_pmt_handlers.end() )
+       {
+               eDebug("[eDVBCIInterfaces] usedby %p", it->usedby);
+               if (!it->usedby)
+               {
+                       // HACK this assigns ALL RUNNING SERVICES to the first free CI !!!
+                       for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
+                       {
+                               eDVBCISlot **usedby = &it->usedby;
+                               *usedby = ci_it;
+                               (*usedby)->resetPrevSentCAPMTVersion();
+                               break;
+                       }
+               }
+               if (it->usedby)
+                       it->usedby->sendCAPMT(pmthandler);
+       }
+}
+
 int eDVBCIInterfaces::getMMIState(int slotid)
 {
        eDVBCISlot *slot;
@@ -205,6 +282,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
 
        application_manager = 0;
        mmi_session = 0;
+       ca_manager = 0;
        
        slotid = nr;
 
@@ -294,4 +372,69 @@ int eDVBCISlot::answerEnq(int answer, char *value)
        return 0;
 }
 
+int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
+{
+       const std::vector<uint16_t> &caids = ids.empty() && ca_manager ? ca_manager->getCAIDs() : ids;
+       ePtr<eTable<ProgramMapSection> > ptr;
+       if (pmthandler->getPMT(ptr))
+               return -1;
+       else
+       {
+               eDVBTableSpec table_spec;
+               ptr->getSpec(table_spec);
+               int pmt_version = table_spec.version & 0x1F; // just 5 bits
+               if ( pmt_version == prev_sent_capmt_version )
+               {
+                       eDebug("[eDVBCISlot] dont sent self capmt version twice");
+                       return -1;
+               }
+               std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
+               if ( i == ptr->getSections().end() )
+                       return -1;
+               else
+               {
+                       unsigned char raw_data[2048];
+                       CaProgramMapSection capmt(*i++, prev_sent_capmt_version != 0xFF ? 0x05 /*update*/ : 0x03 /*only*/, 0x01, caids );
+                       while( i != ptr->getSections().end() )
+                       {
+               //                      eDebug("append");
+                               capmt.append(*i++);
+                       }
+                       capmt.writeToBuffer(raw_data);
+#if 1
+// begin calc capmt length
+                       int wp=0;
+                       if ( raw_data[3] & 0x80 )
+                       {
+                               int i=0;
+                               int lenbytes = raw_data[3] & ~0x80;
+                               while(i < lenbytes)
+                                       wp |= (raw_data[4+i] << (8 * i++));
+                               wp+=4;
+                               wp+=lenbytes;
+                       }
+                       else
+                       {
+                               wp = raw_data[3];
+                               wp+=4;
+                       }
+// end calc capmt length
+                       if (!ca_manager)
+                               eDebug("no ca_manager !!! dump unfiltered capmt:");
+                       else
+                               eDebug("ca_manager %p dump capmt:", ca_manager);
+                       for(int i=0;i<wp;i++)
+                               eDebugNoNewLine("%02x ", raw_data[i]);
+                       eDebug("");
+#endif
+                       if (ca_manager)
+                       {
+                               // TODO SEND buffer to CI ( add session number, add tag )
+                               prev_sent_capmt_version = pmt_version;
+                       }
+               }
+       }
+       
+}
+
 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");
index 224ecde80258bb40b7c401733eeb7694f3f353fd..1df87eaae49ee60c2cd48c74b40292a0359757b4 100644 (file)
@@ -3,10 +3,13 @@
 
 #include <lib/base/ebase.h>
 
+#include <set>
+
 class eDVBCISession;
 class eDVBCIApplicationManagerSession;
 class eDVBCICAManagerSession;
 class eDVBCIMMISession;
+class eDVBServicePMTHandler;
 
 class eDVBCISlot: public iObject, public Object
 {
@@ -18,7 +21,8 @@ private:
        eSocketNotifier *notifier;
 
        int state;
-       enum {stateRemoved, stateInserted};     
+       enum {stateRemoved, stateInserted};
+       uint8_t prev_sent_capmt_version;
 public:
        eDVBCISlot(eMainloop *context, int nr);
        ~eDVBCISlot();
@@ -37,8 +41,29 @@ public:
        int answerText(int answer);
        int answerEnq(int answer, char *value);
        int getMMIState();
+       int sendCAPMT(eDVBServicePMTHandler *ptr, const std::vector<uint16_t> &caids=std::vector<uint16_t>());
+       uint8_t getPrevSentCAPMTVersion() const { return prev_sent_capmt_version; }
+       void resetPrevSentCAPMTVersion() { prev_sent_capmt_version = 0xFF; }
+};
+
+struct CIPmtHandler
+{
+       eDVBServicePMTHandler *pmthandler;
+       eDVBCISlot *usedby;
+       CIPmtHandler()
+               :pmthandler(NULL), usedby(NULL)
+       {}
+       CIPmtHandler( const CIPmtHandler &x )
+               :pmthandler(x.pmthandler), usedby(x.usedby)
+       {}
+       CIPmtHandler( eDVBServicePMTHandler *ptr )
+               :pmthandler(ptr), usedby(NULL)
+       {}
+       bool operator<(const CIPmtHandler &x) const { return x.pmthandler < pmthandler; }
 };
 
+typedef std::set<CIPmtHandler> PMTHandlerSet;
+
 class eDVBCIInterfaces
 {
 DECLARE_REF(eDVBCIInterfaces);
@@ -46,10 +71,16 @@ DECLARE_REF(eDVBCIInterfaces);
 private:
        eSmartPtrList<eDVBCISlot>       m_slots;
        eDVBCISlot *getSlot(int slotid);
+
+       PMTHandlerSet m_pmt_handlers; 
 public:
        eDVBCIInterfaces();
        ~eDVBCIInterfaces();
 
+       void addPMTHandler(eDVBServicePMTHandler *pmthandler);
+       void removePMTHandler(eDVBServicePMTHandler *pmthandler);
+       void gotPMT(eDVBServicePMTHandler *pmthandler);
+
        static eDVBCIInterfaces *getInstance();
        
        int reset(int slot);
index 2ad1f1e363bb36c06a31ccd214138e78ae24477c..d700b0a1e10162b6b5d065b2f28f8ccab093bacc 100644 (file)
@@ -18,7 +18,7 @@ int eDVBCICAManagerSession::receivedAPDU(const unsigned char *tag, const void *d
                        for (int i=0; i<len; i+=2)
                        {
                                printf("%04x ", (((const unsigned char*)data)[i]<<8)|(((const unsigned char*)data)[i+1]));
-                               caids.insert((((const unsigned char*)data)[i]<<8)|(((const unsigned char*)data)[i+1]));
+                               caids.push_back((((const unsigned char*)data)[i]<<8)|(((const unsigned char*)data)[i+1]));
                        }
                        printf("\n");
                        break;
index 7a278539dfa49ca8ccc1e080d43b8a7885b10c8a..c09997c25e67faf408b4d9601e746cf0a19753c1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __dvbci_dvbci_camgr_h
 #define __dvbci_dvbci_camgr_h
 
-#include <set>
+#include <vector>
 
 #include <lib/dvb_ci/dvbci_session.h>
 
@@ -10,10 +10,11 @@ class eDVBCICAManagerSession: public eDVBCISession
        enum {
                stateFinal=statePrivate,
        };
-       std::set<int> caids;
+       std::vector<uint16_t> caids;
        int receivedAPDU(const unsigned char *tag, const void *data, int len);
        int doAction();
 public:
+       const std::vector<uint16_t> &getCAIDs() const { return caids; }
 };
 
 #endif