}
eDVBService::eDVBService()
- :m_flags(0)
+ :m_cache(0), m_flags(0)
{
- memset(m_cache, -1, sizeof(m_cache));
}
eDVBService::~eDVBService()
{
-}
-
-bool eDVBService::cacheEmpty()
-{
- for (int i=0; i < cacheMax; ++i)
- if (m_cache[i] != -1)
- return false;
- return true;
+ delete [] m_cache;
}
eDVBService &eDVBService::operator=(const eDVBService &s)
m_service_name_sort = s.m_service_name_sort;
m_provider_name = s.m_provider_name;
m_flags = s.m_flags;
-// m_ca = s.m_ca;
- memcpy(m_cache, s.m_cache, sizeof(m_cache));
+ m_ca = s.m_ca;
+ copyCache(s.m_cache);
return *this;
}
return res;
}
+bool eDVBService::cacheEmpty()
+{
+ if (m_cache)
+ for (int i=0; i < cacheMax; ++i)
+ if (m_cache[i] != -1)
+ return false;
+ return true;
+}
+
+void eDVBService::initCache()
+{
+ m_cache = new int[cacheMax];
+ memset(m_cache, -1, sizeof(int) * cacheMax);
+}
+
+void eDVBService::copyCache(int *source)
+{
+ if (source)
+ {
+ if (!m_cache)
+ m_cache = new int[cacheMax];
+ memcpy(m_cache, source, cacheMax * sizeof(int));
+ }
+ else
+ {
+ delete [] m_cache;
+ m_cache = 0;
+ }
+}
+
int eDVBService::getCacheEntry(cacheID id)
{
- if (id >= cacheMax)
+ if (id >= cacheMax || !m_cache)
return -1;
return m_cache[id];
}
void eDVBService::setCacheEntry(cacheID id, int pid)
{
+ if (!m_cache)
+ initCache();
if (id < cacheMax)
m_cache[id] = pid;
}
{
int cid, val;
sscanf(v.c_str(), "%02d%04x", &cid, &val);
- s->m_cache[cid]=val;
- }/* else if (p == 'C')
+ s->setCacheEntry(cid,val);
+ } else if (p == 'C')
{
int val;
sscanf(v.c_str(), "%04x", &val);
- s->m_ca.insert(val);
- }*/
+ s->m_ca.push_front((uint16_t)val);
+ }
}
addService(ref, s);
}
// write cached pids
for (int x=0; x < eDVBService::cacheMax; ++x)
- if (i->second->m_cache[x] != -1)
- fprintf(f, ",c:%02d%04x", x, i->second->m_cache[x]);
+ {
+ int entry = i->second->getCacheEntry(x);
+ if (entry != -1)
+ fprintf(f, ",c:%02d%04x", x, entry);
+ }
-/*
// write cached ca pids
- for (std::set<int>::const_iterator ca(i->second->m_ca.begin());
+ for (CAID_LIST::const_iterator ca(i->second->m_ca.begin());
ca != i->second->m_ca.end(); ++ca)
fprintf(f, ",C:%04x", *ca);
-*/
if (i->second->m_flags)
fprintf(f, ",f:%x", i->second->m_flags);
if (tmp==3)
{
eServiceReferenceDVB ref;
- if (!pmthandler->getService(ref))
+ if (!pmthandler->getServiceReference(ref))
{
int pid = (*es)->getPid();
messages.send(Message(Message::got_private_pid, ref, pid));
#include <libsig_comp.h>
#include <connection.h>
+#if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || __GNUC__ == 4 ) // check if gcc version >= 3.1
+#include <ext/slist>
+#define CAID_LIST __gnu_cxx::slist<uint16_t>
+#else
+#include <slist>
+#define CAID_LIST std::slist<uint16_t>
+#endif
+
struct eBouquet
{
std::string m_bouquet_name;
class eDVBService: public iStaticServiceInformation
{
DECLARE_REF(eDVBService);
+ int *m_cache;
+ void initCache();
+ void copyCache(int *source);
public:
enum cacheID
{
bool usePMT() const { return !(m_flags & dxNoDVB); }
-// std::set<int> m_ca;
+ CAID_LIST m_ca;
- int m_cache[cacheMax];
virtual ~eDVBService();
eDVBService &operator=(const eDVBService &);
{
serviceEvent(eventNewProgramInfo);
eEPGCache::getInstance()->PMTready(this);
- if (!m_pvr_channel)
+ if (!m_pvr_channel) // don't send campmt to camd.socket for playbacked services
{
- if(!m_ca_servicePtr) // don't send campmt to camd.socket for playbacked services
+ if(!m_ca_servicePtr)
{
int demuxes[2] = {0,0};
uint8_t tmp;
else
demuxes[1]=demuxes[0];
eDVBCAService::register_service(m_reference, demuxes, m_ca_servicePtr);
- eDVBCIInterfaces::getInstance()->addPMTHandler(this);
+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
}
- eDVBCIInterfaces::getInstance()->gotPMT(this);
+ else
+ eDVBCIInterfaces::getInstance()->gotPMT(this);
}
if (m_ca_servicePtr)
{
{
PyObject *ret=0;
- ePtr<eTable<ProgramMapSection> > ptr;
+ program prog;
- if ( ((m_service && m_service->usePMT()) || !m_service) && !m_PMT.getCurrent(ptr))
+ if ( !getProgramInfo(prog) )
{
- uint16_t caids[255];
- memset(caids, 0, sizeof(caids));
- std::vector<ProgramMapSection*>::const_iterator i = ptr->getSections().begin();
- for (; i != ptr->getSections().end(); ++i)
- {
- const ProgramMapSection &pmt = **i;
- ElementaryStreamInfoConstIterator es = pmt.getEsInfo()->begin();
- for (; es != pmt.getEsInfo()->end(); ++es)
- {
- for (DescriptorConstIterator desc = (*es)->getDescriptors()->begin();
- desc != (*es)->getDescriptors()->end(); ++desc)
- {
- switch ((*desc)->getTag())
- {
- case CA_DESCRIPTOR:
- {
- const CaDescriptor *cadescr = (const CaDescriptor*)*desc;
- uint16_t caid = cadescr->getCaSystemId();
- int idx=0;
- while (caids[idx] && caids[idx] != caid)
- ++idx;
- caids[idx]=caid;
- break;
- }
- }
- }
- }
- for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
- desc != pmt.getDescriptors()->end(); ++desc)
- {
- switch ((*desc)->getTag())
- {
- case CA_DESCRIPTOR:
- {
- const CaDescriptor *cadescr = (const CaDescriptor*)*desc;
- uint16_t caid = cadescr->getCaSystemId();
- int idx=0;
- while (caids[idx] && caids[idx] != caid)
- ++idx;
- caids[idx]=caid;
- break;
- }
- }
- }
- }
- int cnt=0;
- while (caids[cnt])
- ++cnt;
+ int cnt=prog.caids.size();
if (cnt)
{
ret=PyList_New(cnt);
+ std::set<uint16_t>::iterator it(prog.caids.begin());
while(cnt--)
- PyList_SET_ITEM(ret, cnt, PyInt_FromLong(caids[cnt]));
+ PyList_SET_ITEM(ret, cnt, PyInt_FromLong(*it++));
}
}
- if (!ret)
- ret=PyList_New(0);
-
- return ret;
+ return ret ? ret : PyList_New(0);
}
int eDVBServicePMTHandler::getProgramInfo(struct program &program)
program.videoStreams.clear();
program.audioStreams.clear();
program.pcrPid = -1;
- program.isCrypted = false;
program.pmtPid = -1;
program.textPid = -1;
program.audioChannel = m_service ? m_service->getCacheEntry(eDVBService::cACHANNEL) : -1;
ElementaryStreamInfoConstIterator es;
for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
{
- int isaudio = 0, isvideo = 0, cadescriptors = 0;
+ int isaudio = 0, isvideo = 0;
videoStream video;
audioStream audio;
audio.component_tag=-1;
((StreamIdentifierDescriptor*)*desc)->getComponentTag();
break;
case CA_DESCRIPTOR:
- ++cadescriptors;
+ {
+ CaDescriptor *descr = (CaDescriptor*)(*desc);
+ program.caids.insert(descr->getCaSystemId());
break;
}
+ }
}
break;
}
}
else
continue;
- if ( cadescriptors > 0 )
- program.isCrypted=true;
}
- if ( !program.isCrypted )
+ for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
+ desc != pmt.getDescriptors()->end(); ++desc)
{
- for (DescriptorConstIterator desc = pmt.getDescriptors()->begin();
- desc != pmt.getDescriptors()->end(); ++desc)
+ if ((*desc)->getTag() == CA_DESCRIPTOR)
{
- switch ((*desc)->getTag())
- {
- case CA_DESCRIPTOR:
- program.isCrypted=true;
- break;
- }
+ CaDescriptor *descr = (CaDescriptor*)(*desc);
+ program.caids.insert(descr->getCaSystemId());
}
- break;
}
}
return 0;
++cnt;
program.textPid = tpid;
}
+ CAID_LIST &caids = m_service->m_ca;
+ for (CAID_LIST::iterator it(caids.begin()); it != caids.end(); ++it)
+ program.caids.insert(*it);
if ( cnt )
return 0;
}
ref.getChannelID(chid);
res = m_resourceManager->allocateChannel(chid, m_channel);
eDebug("allocate Channel: res %d", res);
+ eDVBCIInterfaces::getInstance()->addPMTHandler(this);
} else
{
eDVBMetaParser parser;
if (ref.path.empty())
{
delete m_dvb_scan;
- m_dvb_scan = new eDVBScan(m_channel);
+ m_dvb_scan = new eDVBScan(m_channel, false);
m_dvb_scan->connectEvent(slot(*this, &eDVBServicePMTHandler::SDTScanEvent), m_scan_event_connection);
}
} else
{
std::vector<videoStream> videoStreams;
std::vector<audioStream> audioStreams;
- // ca info
+ std::set<uint16_t> caids;
int pcrPid;
int pmtPid;
int textPid;
- bool isCrypted;
+ bool isCrypted() { return !caids.empty(); }
int audioChannel;
};
PyObject *getCaIds();
int getPVRChannel(ePtr<iDVBPVRChannel> &pvr_channel);
- int getService(eServiceReferenceDVB &service) { service = m_reference; return 0; }
+ int getServiceReference(eServiceReferenceDVB &service) { service = m_reference; return 0; }
+ int getService(ePtr<eDVBService> &service) { service = m_service; return 0; }
int getPMT(ePtr<eTable<ProgramMapSection> > &ptr) { return m_PMT.getCurrent(ptr); }
int getChannel(eUsePtr<iDVBChannel> &channel);
#include <lib/base/eerror.h>
#include <lib/base/estring.h>
#include <errno.h>
-#include <set>
-#define SCAN_eDebug(x...) eDebug(x)
-#define SCAN_eDebugNoNewLine(x...) eDebugNoNewLine(x)
+static bool scan_debug;
+#define SCAN_eDebug(x...) if (scan_debug) eDebug(x)
+#define SCAN_eDebugNoNewLine(x...) if (scan_debug) eDebugNoNewLine(x)
DEFINE_REF(eDVBScan);
-eDVBScan::eDVBScan(iDVBChannel *channel)
- :m_channel(channel), m_ready(0), m_flags(0), m_ready_all(readySDT)
- ,m_channel_state(iDVBChannel::state_idle)
+eDVBScan::eDVBScan(iDVBChannel *channel, bool debug)
+ :m_channel(channel), m_channel_state(iDVBChannel::state_idle)
+ ,m_ready(0), m_ready_all(readySDT), m_flags(0)
{
+ scan_debug=debug;
if (m_channel->getDemux(m_demux))
SCAN_eDebug("scan: failed to allocate demux!");
m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
if (m_ch_toScan.empty())
{
-// SCAN_eDebug("no channels left to scan.");
-// SCAN_eDebug("%d channels scanned, %d were unavailable.",
-// m_ch_scanned.size(), m_ch_unavailable.size());
-// SCAN_eDebug("%d channels in database.", m_new_channels.size());
+ SCAN_eDebug("no channels left to scan.");
+ SCAN_eDebug("%d channels scanned, %d were unavailable.",
+ m_ch_scanned.size(), m_ch_unavailable.size());
+ SCAN_eDebug("%d channels in database.", m_new_channels.size());
m_event(evtFinish);
return -ENOENT;
}
dvb_service->m_service_name_sort = service->second->m_service_name_sort;
}
dvb_service->m_provider_name = service->second->m_provider_name;
-
+ if (service->second->m_ca.size())
+ dvb_service->m_ca = service->second->m_ca;
if (!dontRemoveOldFlags) // do not remove new found flags when not wished
dvb_service->m_flags &= ~eDVBService::dxNewFound;
}
SCAN_eDebug("name '%s', provider_name '%s'", service->m_service_name.c_str(), service->m_provider_name.c_str());
break;
}
-/*
case CA_IDENTIFIER_DESCRIPTOR:
{
CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
for (CaSystemIdList::const_iterator i(caids.begin()); i != caids.end(); ++i)
{
SCAN_eDebugNoNewLine("%04x ", *i);
- service->m_ca.insert(*i);
+ service->m_ca.push_front(*i);
}
SCAN_eDebug("");
break;
}
-*/
default:
SCAN_eDebug("descr<%x>", (*desc)->getTag());
break;
int m_flags;
public:
- eDVBScan(iDVBChannel *channel);
+ eDVBScan(iDVBChannel *channel, bool debug=false);
~eDVBScan();
enum { scanNetworkSearch = 1, scanSearchBAT = 2, scanRemoveServices = 4, scanDontRemoveFeeds=8 };
return -1;
eDVBCISession::deleteSessions(slot);
+ ciRemoved(slot);
return slot->reset();
}
return -1;
int tunernum = 0;
- if (enable)
+ PMTHandlerList::iterator it = m_pmt_handlers.begin();
+ while (it != m_pmt_handlers.end())
{
- PMTHandlerList::iterator it = m_pmt_handlers.begin();
- while (it != m_pmt_handlers.end())
+ if ( it->cislot == slot )
{
- if ( it->cislot == slot )
+ eDVBServicePMTHandler *pmthandler = it->pmthandler;
+ eUsePtr<iDVBChannel> channel;
+ if (!pmthandler->getChannel(channel))
{
- eDVBServicePMTHandler *pmthandler = it->pmthandler;
- eUsePtr<iDVBChannel> channel;
- if (!pmthandler->getChannel(channel))
+ ePtr<iDVBFrontend> frontend;
+ if (!channel->getFrontend(frontend))
{
- ePtr<iDVBFrontend> frontend;
- if (!channel->getFrontend(frontend))
- {
- eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
- tunernum = fe->getID();
- }
+ eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
+ tunernum = fe->getID();
}
- break;
}
- ++it;
+ break;
}
+ ++it;
}
return slot->enableTS(enable, tunernum);
}
if( (slot = getSlot(slotid)) == 0 )
return -1;
- slot->resetPrevSentCAPMTVersion();
- PMTHandlerList::iterator it = m_pmt_handlers.begin();
- while (it != m_pmt_handlers.end())
- {
- if ( it->cislot == slot )
- {
- slot->sendCAPMT(it->pmthandler); // send capmt
- break;
- }
- ++it;
- }
+ slot->removeService();
- return slot->initialize();
+ return sendCAPMT(slotid);
}
int eDVBCIInterfaces::sendCAPMT(int slotid)
if( (slot = getSlot(slotid)) == 0 )
return -1;
- slot->resetPrevSentCAPMTVersion();
PMTHandlerList::iterator it = m_pmt_handlers.begin();
while (it != m_pmt_handlers.end())
{
if ( it->cislot == slot )
- {
slot->sendCAPMT(it->pmthandler); // send capmt
- return 0;
- }
++it;
}
- return -1;
+ return 0;
}
int eDVBCIInterfaces::startMMI(int slotid)
return slot->cancelEnq();
}
-void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
+void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
{
- CIPmtHandler new_handler(pmthandler);
-
- eServiceReferenceDVB service;
- pmthandler->getService(service);
-
- eDebug("[eDVBCIInterfaces] addPMTHandler %s", service.toString().c_str());
-
- // HACK the first service get the CI..
- eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin());
- for (; ci_it != m_slots.end(); ++ci_it)
+ for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
+ it != m_pmt_handlers.end(); ++it)
{
- if (ci_it->use_count)
- continue;
- ci_it->use_count=1;
- new_handler.cislot = ci_it;
- new_handler.cislot->resetPrevSentCAPMTVersion();
+ if (it->cislot == slot)
+ {
+ eServiceReferenceDVB ref;
+ it->pmthandler->getServiceReference(ref);
+ slot->removeService(ref.getServiceID().get());
+ if (!--slot->use_count)
+ enableTS(slot->getSlotID(), 0);
+ it->cislot=0;
+ }
}
+}
- if (ci_it == m_slots.end())
+void eDVBCIInterfaces::recheckPMTHandlers()
+{
+// eDebug("recheckPMTHAndlers()");
+ for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
+ it != m_pmt_handlers.end(); ++it)
{
- PMTHandlerList::iterator it = m_pmt_handlers.begin();
- while (it != m_pmt_handlers.end())
+ CAID_LIST caids;
+ ePtr<eDVBService> service;
+ eServiceReferenceDVB ref;
+ eDVBServicePMTHandler *pmthandler = it->pmthandler;
+ eDVBServicePMTHandler::program p;
+
+ pmthandler->getServiceReference(ref);
+ pmthandler->getService(service);
+ if (!pmthandler->getProgramInfo(p))
{
- eServiceReferenceDVB ref;
- it->pmthandler->getService(ref);
- if ( service == ref && it->cislot )
+ int cnt=0;
+ for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
+ caids.push_front(*x);
+ if (service && cnt)
+ service->m_ca = caids;
+ }
+
+ if (it->cislot)
+ continue; // already running
+
+ if (service)
+ caids = service->m_ca;
+
+ if (!caids.empty())
+ {
+ for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
{
- new_handler.cislot = it->cislot;
- ++new_handler.cislot->use_count;
- break;
+ if (ci_it->getState() == eDVBCISlot::stateInvalid)
+ ci_it->reset();
+
+ bool useThis=false;
+ eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
+ if (ca_manager)
+ {
+ const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
+ for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
+ {
+ std::vector<uint16_t>::const_iterator z =
+ std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
+ if ( z != ci_caids.end() && *z == *ca )
+ {
+ eDebug("found ci for caid %04x", *z);
+ useThis=true;
+ break;
+ }
+ }
+ }
+
+ if (useThis)
+ {
+ bool send_ca_pmt = false;
+ if (ci_it->use_count) // check if this CI can descramble more than one service
+ {
+ PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
+ while (tmp != m_pmt_handlers.end())
+ {
+ if ( tmp->cislot )
+ {
+ bool canHandleMultipleServices=false;
+ eServiceReferenceDVB ref2;
+ tmp->pmthandler->getServiceReference(ref2);
+ eDVBChannelID s1, s2;
+ if (ref != ref2)
+ {
+ ref.getChannelID(s1);
+ ref2.getChannelID(s2);
+ // FIXME .. build a "ci can handle multiple services" config entry
+ // Yes / No / Auto
+ if ( eDVBCI_UI::getInstance()->getAppName(ci_it->getSlotID()) == "AlphaCrypt" )
+ {
+ canHandleMultipleServices = true;
+ eDebug("Alphacrypt can handle multiple services");
+ }
+ }
+ if (ref == ref2 || (s1 == s2 && canHandleMultipleServices) )
+ {
+ it->cislot = tmp->cislot;
+ ++it->cislot->use_count;
+ send_ca_pmt = true;
+// eDebug("usecount now %d", it->cislot->use_count);
+ break;
+ }
+ }
+ ++tmp;
+ }
+ }
+ else
+ {
+ ci_it->use_count=1;
+ it->cislot = ci_it;
+// eDebug("usecount now %d", it->cislot->use_count);
+ enableTS(ci_it->getSlotID(), 1);
+ send_ca_pmt = true;
+ }
+ if (send_ca_pmt)
+ gotPMT(pmthandler);
+ }
}
- ++it;
}
}
+}
+
+void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
+{
+ // check if this pmthandler is already registered
+ PMTHandlerList::iterator it = m_pmt_handlers.begin();
+ while (it != m_pmt_handlers.end())
+ {
+ if ( *it++ == pmthandler )
+ return;
+ }
+
+ eServiceReferenceDVB ref;
+ pmthandler->getServiceReference(ref);
+ eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
- m_pmt_handlers.push_back(new_handler);
+ m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
+ recheckPMTHandlers();
}
void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
if (it != m_pmt_handlers.end())
{
eDVBCISlot *slot = it->cislot;
-// eDVBServicePMTHandler *pmthandler = it->pmthandler;
+ eDVBServicePMTHandler *pmthandler = it->pmthandler;
m_pmt_handlers.erase(it);
- if (slot && !--slot->use_count)
+
+ eServiceReferenceDVB service_to_remove;
+ pmthandler->getServiceReference(service_to_remove);
+
+ bool sameServiceExist=false;
+ for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
{
-#if 0
- eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt");
- std::vector<uint16_t> caids;
- caids.push_back(0xFFFF);
- slot->resetPrevSentCAPMTVersion();
- slot->sendCAPMT(pmthandler, caids);
-#endif
- // check if another service is running
- it = m_pmt_handlers.begin();
- while (it != m_pmt_handlers.end())
+ eServiceReferenceDVB ref;
+ i->pmthandler->getServiceReference(ref);
+ if ( ref == service_to_remove )
{
- if ( !it->cislot )
- {
- it->cislot = slot;
- ++slot->use_count;
- slot->resetPrevSentCAPMTVersion();
- slot->sendCAPMT(it->pmthandler);
- break;
- }
- ++it;
+ sameServiceExist=true;
+ break;
}
}
+
+ if (slot && !sameServiceExist)
+ {
+ if (slot->getNumOfServices() > 1) // fixme make it dependend of "ci can handle more than one service"
+ {
+ eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
+ service_to_remove.toString().c_str());
+ std::vector<uint16_t> caids;
+ caids.push_back(0xFFFF);
+ slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service
+ }
+ slot->removeService(service_to_remove.getServiceID().get());
+ }
+
+ if (slot && !--slot->use_count)
+ {
+ ASSERT(!slot->getNumOfServices());
+ enableTS(slot->getSlotID(),0);
+ }
}
+ // check if another service is waiting for the CI
+ recheckPMTHandlers();
}
void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
{
eDebug("[eDVBCIInterfaces] gotPMT");
PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
- eServiceReferenceDVB service;
- if ( it != m_pmt_handlers.end() && it->cislot)
+ if (it != m_pmt_handlers.end() && it->cislot)
it->cislot->sendCAPMT(pmthandler);
}
int eDVBCISlot::send(const unsigned char *data, size_t len)
{
- int res;
+ int res=0;
//int i;
//printf("< ");
//for(i=0;i<len;i++)
// printf("%02x ",data[i]);
//printf("\n");
- res = ::write(fd, data, len);
-
- //printf("write() %d\n",res);
+ if (sendqueue.empty())
+ res = ::write(fd, data, len);
- notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
+ if (res < 0 || (unsigned int)res != len)
+ {
+ unsigned char *d = new unsigned char[len];
+ memcpy(d, data, len);
+ sendqueue.push( queueData(d, len) );
+ notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
+ }
return res;
}
void eDVBCISlot::data(int what)
{
+ if (state == stateInvalid)
+ return;
if(what == eSocketNotifier::Priority) {
if(state != stateRemoved) {
state = stateRemoved;
- enableTS(0);
printf("ci removed\n");
+ while(sendqueue.size())
+ {
+ delete [] sendqueue.top().data;
+ sendqueue.pop();
+ }
+ eDVBCIInterfaces::getInstance()->ciRemoved(this);
eDVBCISession::deleteSessions(this);
notifier->setRequested(eSocketNotifier::Read);
//HACK
return;
}
- __u8 data[4096];
- int r;
- r = ::read(fd, data, 4096);
-
if(state != stateInserted) {
- state = stateInserted;
eDebug("ci inserted");
-
- //HACK
+ state = stateInserted;
+// HACK
eDVBCI_UI::getInstance()->setState(0,1);
-
+ notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
/* enable PRI to detect removal or errors */
- notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Write);
}
- if(r > 0) {
- //int i;
- //printf("> ");
- //for(i=0;i<r;i++)
- // printf("%02x ",data[i]);
- //printf("\n");
- eDVBCISession::receiveData(this, data, r);
- notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Write);
- return;
+ if (what & eSocketNotifier::Read) {
+ __u8 data[4096];
+ int r;
+ r = ::read(fd, data, 4096);
+ if(r > 0) {
+// int i;
+// printf("> ");
+// for(i=0;i<r;i++)
+// printf("%02x ",data[i]);
+// printf("\n");
+ eDVBCISession::receiveData(this, data, r);
+ eDVBCISession::pollAll();
+ return;
+ }
}
-
- if(what == eSocketNotifier::Write) {
- if(eDVBCISession::pollAll() == 0) {
- notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority);
+ else if (what & eSocketNotifier::Write) {
+ if (!sendqueue.empty()) {
+ const queueData &qe = sendqueue.top();
+ int res = ::write(fd, qe.data, qe.len);
+ if (res >= 0 && (unsigned int)res == qe.len)
+ {
+ delete [] qe.data;
+ sendqueue.pop();
+ }
}
+ else
+ notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
}
}
fd = ::open(filename, O_RDWR | O_NONBLOCK);
eDebug("eDVBCISlot has fd %d", fd);
-
- state = stateInserted;
+ state = stateInvalid;
if (fd >= 0)
{
- notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority);
+ notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
CONNECT(notifier->activated, eDVBCISlot::data);
} else
{
perror(filename);
}
+
+ enableTS(0, 0);
}
eDVBCISlot::~eDVBCISlot()
{
- enableTS(0);
}
void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
{
printf("edvbcislot: reset requested\n");
- enableTS(0);
+ if (state == stateInvalid)
+ {
+ unsigned char buf[256];
+ eDebug("ci flush");
+ while(::read(fd, buf, 256)>0);
+ state = stateResetted;
+ }
- ioctl(fd, 0);
+ while(sendqueue.size())
+ {
+ delete [] sendqueue.top().data;
+ sendqueue.pop();
+ }
- return 0;
-}
+ ioctl(fd, 0);
-int eDVBCISlot::initialize()
-{
- printf("edvbcislot: initialize()\n");
return 0;
}
eDVBTableSpec table_spec;
ptr->getSpec(table_spec);
int pmt_version = table_spec.version & 0x1F; // just 5 bits
- if ( pmt_version == prev_sent_capmt_version )
+
+ eServiceReferenceDVB ref;
+ pmthandler->getServiceReference(ref);
+ uint16_t program_number = ref.getServiceID().get();
+ std::map<uint16_t, uint8_t>::iterator it =
+ running_services.find(program_number);
+
+ if ( it != running_services.end() &&
+ (pmt_version == it->second) &&
+ !(caids.size() == 1 && caids[0] == 0xFFFF) )
{
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 );
+
+// eDebug("send %s capmt for service %04x",
+// it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
+// program_number);
+
+ CaProgramMapSection capmt(*i++,
+ it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
while( i != ptr->getSections().end() )
{
// eDebug("append");
hlen = 4;
}
// end calc capmt length
- eDebug("ca_manager %p dump capmt:", ca_manager);
- for(int i=0;i<wp;i++)
- eDebugNoNewLine("%02x ", raw_data[i]);
- eDebug("");
+// eDebug("ca_manager %p dump capmt:", ca_manager);
+// for(int i=0;i<wp;i++)
+// eDebugNoNewLine("%02x ", raw_data[i]);
+// eDebug("");
#endif
+ if (caids.size() == 1 && caids[0] == 0xFFFF)
+ {
+// eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
+ raw_data[hlen+3] &= ~0x3E;
+ raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
+// eDebug(" new version is %02x", raw_data[hlen+3]);
+ }
+
//dont need tag and lenfield
ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
- prev_sent_capmt_version = pmt_version;
+ running_services[program_number] = pmt_version;
}
}
return 0;
}
+void eDVBCISlot::removeService(uint16_t program_number)
+{
+ if (program_number == 0xFFFF)
+ running_services.clear(); // remove all
+ else
+ running_services.erase(program_number); // remove single service
+}
+
int eDVBCISlot::enableTS(int enable, int tuner)
{
- printf("eDVBCISlot::enableTS(%d %d)\n", enable, tuner);
+// printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
+// printf("eDVBCISlot::enableTS(%d %d)\n", enable, tuner);
FILE *input0, *input1, *ci;
if((input0 = fopen("/proc/stb/tsmux/input0", "wb")) == NULL) {
return 0;
}
-void eDVBCISlot::resendCAPMT()
-{
- eDVBCIInterfaces::getInstance()->sendCAPMT(slotid);
-}
-
eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");
#include <lib/base/ebase.h>
#include <set>
+#include <queue>
class eDVBCISession;
class eDVBCIApplicationManagerSession;
class eDVBServicePMTHandler;
class eDVBCISlot;
+struct queueData
+{
+ __u8 prio;
+ unsigned char *data;
+ unsigned int len;
+ queueData( unsigned char *data, unsigned int len, __u8 prio = 0 )
+ :prio(prio), data(data), len(len)
+ {
+
+ }
+ bool operator < ( const struct queueData &a ) const
+ {
+ return prio < a.prio;
+ }
+};
+
class eDVBCISlot: public iObject, public Object
{
DECLARE_REF(eDVBCISlot);
eSocketNotifier *notifier;
int state;
- enum {stateRemoved, stateInserted};
- uint8_t prev_sent_capmt_version;
+ std::map<uint16_t, uint8_t> running_services;
eDVBCIApplicationManagerSession *application_manager;
eDVBCICAManagerSession *ca_manager;
eDVBCIMMISession *mmi_session;
+ std::priority_queue<queueData> sendqueue;
public:
+ enum {stateRemoved, stateInserted, stateInvalid, stateResetted};
int use_count;
eDVBCISlot(eMainloop *context, int nr);
eDVBCIMMISession *getMMIManager() { return mmi_session; }
eDVBCICAManagerSession *getCAManager() { return ca_manager; }
+ int getState() { return state; }
int getSlotID();
int reset();
- int initialize();
int startMMI();
int stopMMI();
int answerText(int answer);
int answerEnq(char *value);
int cancelEnq();
int getMMIState();
- void resendCAPMT();
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; }
+ void removeService(uint16_t program_number=0xFFFF);
+ int getNumOfServices() { return running_services.size(); }
int enableTS(int enable, int tuner=0);
DECLARE_REF(eDVBCIInterfaces);
static eDVBCIInterfaces *instance;
private:
- eSmartPtrList<eDVBCISlot> m_slots;
+ eSmartPtrList<eDVBCISlot> m_slots;
eDVBCISlot *getSlot(int slotid);
PMTHandlerList m_pmt_handlers;
void addPMTHandler(eDVBServicePMTHandler *pmthandler);
void removePMTHandler(eDVBServicePMTHandler *pmthandler);
+ void recheckPMTHandlers();
void gotPMT(eDVBServicePMTHandler *pmthandler);
+ void ciRemoved(eDVBCISlot *slot);
static eDVBCIInterfaces *getInstance();
for (int i = 0; i < dl; ++i)
printf("%c", ((unsigned char*)data)[i+6]);
printf("\n");
-
- eDVBCI_UI::getInstance()->setState(0,2);
- eDVBCI_UI::getInstance()->setAppName(0,str);
+
+ eDVBCI_UI::getInstance()->setState(slot->getSlotID(), 2);
+
+ eDVBCI_UI::getInstance()->setAppName(slot->getSlotID(), str);
break;
}
default:
printf("%04x ", (((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]));
}
+ std::sort(caids.begin(), caids.end());
printf("\n");
- slot->resendCAPMT();
+ eDVBCIInterfaces::getInstance()->recheckPMTHandlers();
break;
default:
printf("unknown APDU tag 9F 80 %02x\n", tag[2]);
{
const unsigned char tag[3]={0x9F, 0x80, 0x32}; // ca_pmt
- sendAPDU(tag, data, len);
-
+ sendAPDU(tag, data, len);
+
return 0;
}
{
DECLARE_REF(eDVBCISession);
static ePtr<eDVBCISession> sessions[SLMS];
- static void eDVBCISession::deleteSessions(const eDVBCISlot *slot);
- static void eDVBCISession::createSession(eDVBCISlot *slot, const unsigned char *resource_identifier, unsigned char &status, ePtr<eDVBCISession> &ptr);
- static void eDVBCISession::sendSPDU(eDVBCISlot *slot, unsigned char tag,const void *data, int len, unsigned short session_nb, const void *apdu=0,int alen=0);
+ static void deleteSessions(const eDVBCISlot *slot);
+ static void createSession(eDVBCISlot *slot, const unsigned char *resource_identifier, unsigned char &status, ePtr<eDVBCISession> &ptr);
+ static void sendSPDU(eDVBCISlot *slot, unsigned char tag,const void *data, int len, unsigned short session_nb, const void *apdu=0,int alen=0);
static void sendOpenSessionResponse(eDVBCISlot *slot,unsigned char session_status, const unsigned char *resource_identifier,unsigned short session_nb);
void recvCreateSessionResponse(const unsigned char *data);
void recvCloseSessionRequest(const unsigned char *data);
eDVBCISlot *slot; //base only
unsigned short session_nb;
virtual int receivedAPDU(const unsigned char *tag, const void *data, int len) = 0;
- void eDVBCISession::sendAPDU(const unsigned char *tag, const void *data=0,int len=0);
- void eDVBCISession::sendSPDU(unsigned char tag, const void *data, int len,const void *apdu=0, int alen=0);
+ void sendAPDU(const unsigned char *tag, const void *data=0,int len=0);
+ void sendSPDU(unsigned char tag, const void *data, int len,const void *apdu=0, int alen=0);
virtual int doAction()=0;
void handleClose();
public:
#include <lib/base/init_num.h>
#include <lib/base/eerror.h>
-eDVBCI_UI *eDVBCI_UI::instance = 0;
+eDVBCI_UI *eDVBCI_UI::instance;
eDVBCI_UI::eDVBCI_UI()
- :mmiScreen(NULL)
- ,mmiTuplePos(0)
- ,mmiScreenReady(0)
{
ASSERT(!instance);
instance = this;
- for(int i=0;i<MAX_SLOTS;i++)
- state[i] = 0; //no module
+ for(int i=0;i<MAX_SLOTS;++i)
+ {
+ slotdata[i].mmiScreen=NULL;
+ slotdata[i].mmiScreenReady=0;
+ slotdata[i].mmiTuplePos=0;
+ slotdata[i].state=0;
+ }
}
eDVBCI_UI::~eDVBCI_UI()
{
- if(mmiScreen)
- Py_DECREF(mmiScreen);
+ for(int i=0;i<MAX_SLOTS;++i)
+ {
+ if (slotdata[i].mmiScreen)
+ Py_DECREF(slotdata[i].mmiScreen);
+ }
}
eDVBCI_UI *eDVBCI_UI::getInstance()
int eDVBCI_UI::getState(int slot)
{
- return state[slot]; //exploit me ;)
+ if (slot < MAX_SLOTS)
+ return slotdata[slot].state;
+ return 0;
}
void eDVBCI_UI::setState(int slot, int newState)
{
- state[slot] = newState;
-
- if(newState == 2) //enable TS
- eDVBCIInterfaces::getInstance()->enableTS(slot, 1);
+ if (slot < MAX_SLOTS)
+ slotdata[slot].state = newState;
}
std::string eDVBCI_UI::getAppName(int slot)
{
- return appName;
+ if (slot < MAX_SLOTS)
+ return slotdata[slot].appName;
+ return "";
}
void eDVBCI_UI::setAppName(int slot, const char *name)
{
- //printf("set name to -%c-\n", name);
- appName = name;
+ if (slot < MAX_SLOTS)
+ slotdata[slot].appName = name;
}
void eDVBCI_UI::setInit(int slot)
{
- eDVBCIInterfaces::getInstance()->sendCAPMT(slot);
+ eDVBCIInterfaces::getInstance()->initialize(slot);
}
void eDVBCI_UI::setReset(int slot)
return 0;
}
-int eDVBCI_UI::initialize(int slot)
-{
- eDVBCIInterfaces::getInstance()->initialize(slot);
- return 0;
-}
-
int eDVBCI_UI::answerMenu(int slot, int answer)
{
eDVBCIInterfaces::getInstance()->answerText(slot, answer);
int eDVBCI_UI::availableMMI(int slot)
{
- return mmiScreenReady;
+ if (slot < MAX_SLOTS)
+ return slotdata[slot].mmiScreenReady;
+ return false;
}
int eDVBCI_UI::mmiScreenEnq(int slot, int blind, int answerLen, char *text)
{
- mmiScreenReady = 0;
+ if (slot >= MAX_SLOTS)
+ return 0;
- if(mmiScreen)
- Py_DECREF(mmiScreen);
- mmiScreen = PyList_New(2);
+ slot_ui_data &data = slotdata[slot];
+
+ data.mmiScreenReady = 0;
+
+ if (data.mmiScreen)
+ Py_DECREF(data.mmiScreen);
+ data.mmiScreen = PyList_New(2);
PyObject *tuple = PyTuple_New(1);
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("ENQ"));
- PyList_SET_ITEM(mmiScreen, 0, tuple);
+ PyList_SET_ITEM(data.mmiScreen, 0, tuple);
tuple = PyTuple_New(4);
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("PIN"));
PyTuple_SET_ITEM(tuple, 2, PyString_FromString(text));
PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(blind));
- PyList_SET_ITEM(mmiScreen, 1, tuple);
+ PyList_SET_ITEM(data.mmiScreen, 1, tuple);
- mmiScreenReady = 1;
+ data.mmiScreenReady = 1;
return 0;
}
int eDVBCI_UI::mmiScreenBegin(int slot, int listmenu)
{
+ if (slot >= MAX_SLOTS)
+ return 0;
+
printf("eDVBCI_UI::mmiScreenBegin\n");
- mmiScreenReady = 0;
+ slot_ui_data &data = slotdata[slot];
- if(mmiScreen)
- Py_DECREF(mmiScreen);
- mmiScreen = PyList_New(1);
+ data.mmiScreenReady = 0;
+
+ if (data.mmiScreen)
+ Py_DECREF(data.mmiScreen);
+
+ data.mmiScreen = PyList_New(1);
PyObject *tuple = PyTuple_New(1);
- if(listmenu == 0) //menu
+ if (listmenu == 0) //menu
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("MENU"));
else //list
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("LIST"));
- PyList_SET_ITEM(mmiScreen, 0, tuple);
+ PyList_SET_ITEM(data.mmiScreen, 0, tuple);
- mmiTuplePos = 1;
+ data.mmiTuplePos = 1;
return 0;
}
int eDVBCI_UI::mmiScreenAddText(int slot, int type, char *value)
{
- eDebug("eDVBCI_UI::mmiScreenAddText(%s)",value);
+ if (slot >= MAX_SLOTS)
+ return 0;
+
+ eDebug("eDVBCI_UI::mmiScreenAddText(%s)",value ? value : "");
+
+ slot_ui_data &data = slotdata[slot];
PyObject *tuple = PyTuple_New(3);
- if(type == 0) //title
+ if (type == 0) //title
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("TITLE"));
- else if(type == 1) //subtitle
+ else if (type == 1) //subtitle
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("SUBTITLE"));
- else if(type == 2) //bottom
+ else if (type == 2) //bottom
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("BOTTOM"));
else
PyTuple_SET_ITEM(tuple, 0, PyString_FromString("TEXT"));
PyTuple_SET_ITEM(tuple, 1, PyString_FromString(value));
- if(type > 2)
+ if (type > 2)
PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(type-2));
else
PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(-1));
- PyList_Append(mmiScreen, tuple);
+ PyList_Append(data.mmiScreen, tuple);
Py_DECREF(tuple);
return 0;
int eDVBCI_UI::mmiScreenFinish(int slot)
{
- printf("eDVBCI_UI::mmiScreenFinish\n");
-
- mmiScreenReady = 1;
-
+ if (slot < MAX_SLOTS)
+ {
+ printf("eDVBCI_UI::mmiScreenFinish\n");
+ slotdata[slot].mmiScreenReady = 1;
+ }
return 0;
}
PyObject *eDVBCI_UI::getMMIScreen(int slot)
{
- if(mmiScreenReady)
+ if (slot < MAX_SLOTS)
{
- mmiScreenReady = 0;
- Py_INCREF(mmiScreen);
- return mmiScreen;
+ slot_ui_data &data = slotdata[slot];
+ if (data.mmiScreenReady)
+ {
+ data.mmiScreenReady = 0;
+ Py_INCREF(data.mmiScreen);
+ return data.mmiScreen;
+ }
}
Py_INCREF(Py_None);
return Py_None;
#define _POSIX_C_SOURCE 200112L
#include <Python.h>
-#define MAX_SLOTS 2
+#define MAX_SLOTS 4
-class eDVBCI_UI
+struct slot_ui_data
{
- int state[MAX_SLOTS];
- static eDVBCI_UI *instance;
std::string appName;
+ int state;
PyObject *mmiScreen;
int mmiTuplePos;
int mmiScreenReady;
+};
+
+class eDVBCI_UI
+{
+ static eDVBCI_UI *instance;
+ slot_ui_data slotdata[MAX_SLOTS];
#ifdef SWIG
eDVBCI_UI();
~eDVBCI_UI();
~eDVBCI_UI();
#endif
static eDVBCI_UI *getInstance();
-
+
int getState(int slot);
void setState(int slot, int state);
std::string getAppName(int slot);
void setAppName(int slot, const char *name);
void setInit(int slot);
void setReset(int slot);
- int initialize(int slot);
int startMMI(int slot);
int stopMMI(int slot);
int availableMMI(int slot);
int answerEnq(int slot, char *val);
int cancelEnq(int slot);
- PyObject *eDVBCI_UI::getMMIScreen(int slot);
+ PyObject *getMMIScreen(int slot);
int mmiScreenEnq(int slot, int blind, int answerLen, char *text);
int mmiScreenBegin(int slot, int listmenu);
else:
print "give cancel action to ci"
+ def keyConfigEntry(self, key):
+ try:
+ self["entries"].handleKey(key)
+ except AttributeError:
+ pass
+
def keyNumberGlobal(self, number):
- self["entries"].handleKey(config.key[str(number)])
+ self.keyConfigEntry(config.key[str(number)])
def keyLeft(self):
- self["entries"].handleKey(config.key["prevElement"])
+ self.keyConfigEntry(config.key["prevElement"])
def keyRight(self):
- self["entries"].handleKey(config.key["nextElement"])
+ self.keyConfigEntry(config.key["nextElement"])
def updateList(self, list):
List = self["entries"]
List.l.setList(list)
-
def showWait(self):
self.tag = "WAIT"
self["title"].setText("")
}
}
return -1;
- case sIsCrypted: return program.isCrypted;
+ case sIsCrypted: return program.isCrypted();
case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;