#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)
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);
}
m_PMT.getCurrent(ptr);
eDVBCAService::unregister_service(m_reference, demux_num, ptr);
}
+ eDVBCIInterfaces::getInstance()->removePMTHandler(this);
}
void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
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)
{
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;
#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()
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;
application_manager = 0;
mmi_session = 0;
+ ca_manager = 0;
slotid = nr;
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");
#include <lib/base/ebase.h>
+#include <set>
+
class eDVBCISession;
class eDVBCIApplicationManagerSession;
class eDVBCICAManagerSession;
class eDVBCIMMISession;
+class eDVBServicePMTHandler;
class eDVBCISlot: public iObject, public Object
{
eSocketNotifier *notifier;
int state;
- enum {stateRemoved, stateInserted};
+ enum {stateRemoved, stateInserted};
+ uint8_t prev_sent_capmt_version;
public:
eDVBCISlot(eMainloop *context, int nr);
~eDVBCISlot();
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);
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);