X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/f94e2c9821eb8784ca03b7122485d4720ec6d6e6..d026012d8ba6198d879df68cb4bf6c92c95a633a:/lib/dvb/epgcache.cpp diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp index 6dea73bc..ec2c1172 100644 --- a/lib/dvb/epgcache.cpp +++ b/lib/dvb/epgcache.cpp @@ -8,6 +8,7 @@ #include // for statfs // #include #include +#include int eventData::CacheSize=0; descriptorMap eventData::descriptors; @@ -191,6 +192,7 @@ void eEPGCache::DVBChannelAdded(eDVBChannel *chan) // eDebug("[eEPGCache] add channel %p", chan); channel_data *data = new channel_data(this); data->channel = chan; + data->prevChannelState = -1; singleLock s(channel_map_lock); m_knownChannels.insert( std::pair(chan, data) ); chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn); @@ -256,25 +258,31 @@ void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan) { int state=0; chan->getState(state); - switch (state) + if ( it->second->prevChannelState != state ) { - case iDVBChannel::state_ok: + switch (state) { - eDebug("[eEPGCache] channel %p running", chan); - DVBChannelRunning(chan); - break; - } - case iDVBChannel::state_release: - { - eDebug("[eEPGCache] remove channel %p", chan); - messages.send(Message(Message::leaveChannel, chan)); - while(!it->second->can_delete) - usleep(1000); - delete it->second; - m_knownChannels.erase(it); - // -> gotMessage -> abortEPG - break; + case iDVBChannel::state_ok: + { + eDebug("[eEPGCache] channel %p running", chan); + DVBChannelRunning(chan); + break; + } + case iDVBChannel::state_release: + { + eDebug("[eEPGCache] remove channel %p", chan); + messages.send(Message(Message::leaveChannel, chan)); + while(!it->second->can_delete) + usleep(1000); + delete it->second; + m_knownChannels.erase(it); + // -> gotMessage -> abortEPG + break; + } + default: // ignore all other events + return; } + it->second->prevChannelState = state; } } } @@ -615,13 +623,12 @@ void eEPGCache::thread() nice(4); load(); cleanLoop(); - exec(); + run(); save(); } void eEPGCache::load() { -#if 0 FILE *f = fopen("/hdd/epg.dat", "r"); if (f) { @@ -630,6 +637,7 @@ void eEPGCache::load() int size=0; int cnt=0; bool md5ok=false; +#if 0 if (!md5_file("/hdd/epg.dat", 1, md5)) { FILE *f = fopen("/hdd/epg.dat.md5", "r"); @@ -642,6 +650,7 @@ void eEPGCache::load() } } if ( md5ok ) +#endif { char text1[13]; fread( text1, 13, 1, f); @@ -681,12 +690,10 @@ void eEPGCache::load() fclose(f); } } -#endif } void eEPGCache::save() { -#if 0 struct statfs s; off64_t tmp; if (statfs("/hdd", &s)<0) @@ -733,6 +740,7 @@ void eEPGCache::save() eDebug("%d events written to /hdd/epg.dat", cnt); eventData::save(f); fclose(f); +#if 0 unsigned char md5[16]; if (!md5_file("/hdd/epg.dat", 1, md5)) { @@ -743,8 +751,8 @@ void eEPGCache::save() fclose(f); } } - } #endif + } } eEPGCache::channel_data::channel_data(eEPGCache *ml) @@ -996,8 +1004,8 @@ void eEPGCache::channel_data::readData( const __u8 *data) } } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result ) -// if t == 0 we search the current event... +RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result, int direction) +// if t == -1 we search the current event... { singleLock s(cache_lock); uniqueEPGKey key(service); @@ -1006,62 +1014,63 @@ RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, co eventCache::iterator It = eventDB.find( key ); if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ? { - if (!t) + if (t==-1) t = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); - -// TODO: optimize this.. why we here search first in timemap.. and then in eventmap?? - timeMap::iterator i = It->second.second.lower_bound(t); + timeMap::iterator i = direction <= 0 ? It->second.second.lower_bound(t) : // find > or equal + It->second.second.upper_bound(t); // just > if ( i != It->second.second.end() ) { - if ( i != It->second.second.end() ) + if ( direction < 0 || (direction == 0 && i->second->getStartTime() > t) ) { - if ( t <= i->first+i->second->getDuration() ) + timeMap::iterator x = i; + --x; + if ( x != It->second.second.end() ) { - result = i->second; - return 0; + time_t start_time = x->second->getStartTime(); + if (direction >= 0) + { + if (t < start_time) + return -1; + if (t > (start_time+x->second->getDuration())) + return -1; + } + i = x; } + else + return -1; } - } - - for ( eventMap::iterator i( It->second.first.begin() ); i != It->second.first.end(); i++) - { - int duration = i->second->getDuration(); - time_t begTime = i->second->getStartTime(); - if ( t >= begTime && t <= begTime+duration) // then we have found - { - result = i->second; - return 0; - } + result = i->second; + return 0; } } return -1; } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result ) +RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result, int direction) { singleLock s(cache_lock); const eventData *data=0; - RESULT ret = lookupEventTime(service, t, data); + RESULT ret = lookupEventTime(service, t, data, direction); if ( !ret && data ) result = data->get(); return ret; } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result ) +RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result, int direction) { singleLock s(cache_lock); const eventData *data=0; - RESULT ret = lookupEventTime(service, t, data); + RESULT ret = lookupEventTime(service, t, data, direction); if ( !ret && data ) result = new Event((uint8_t*)data->get()); return ret; } -RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr &result ) +RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr &result, int direction) { singleLock s(cache_lock); const eventData *data=0; - RESULT ret = lookupEventTime(service, t, data); + RESULT ret = lookupEventTime(service, t, data, direction); if ( !ret && data ) { Event ev((uint8_t*)data->get()); @@ -1139,12 +1148,19 @@ RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, if ( begin != -1 ) { m_timemap_cursor = It->second.second.lower_bound(begin); - if ( m_timemap_cursor != It->second.second.end() && m_timemap_cursor != It->second.second.begin() ) + if ( m_timemap_cursor != It->second.second.end() ) { - timeMap::iterator it = m_timemap_cursor; - --it; - if ( (it->second->getStartTime() + it->second->getDuration()) > begin ) - m_timemap_cursor = it; + if ( m_timemap_cursor->second->getStartTime() != begin ) + { + timeMap::iterator x = m_timemap_cursor; + --x; + if ( x != It->second.second.end() ) + { + time_t start_time = x->second->getStartTime(); + if ( begin > start_time && begin < (start_time+x->second->getDuration())) + m_timemap_cursor = x; + } + } } } else @@ -1196,3 +1212,272 @@ RESULT eEPGCache::getNextTimeEntry(ePtr &result) } return -1; } + +void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service, ePtr &ptr, PyObject *nowTime, PyObject *service_name ) +{ + PyObject *tmp=NULL; + int pos=0; + while(pos < argcount) + { + bool inc_refcount=false; + switch(argstring[pos]) + { + case 'I': // Event Id + tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : NULL; + break; + case 'B': // Event Begin Time + tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL; + break; + case 'D': // Event Duration + tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL; + break; + case 'T': // Event Title + tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL; + break; + case 'S': // Event Short Description + tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL; + break; + case 'E': // Event Extended Description + tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL; + break; + case 'C': // Current Time + tmp = nowTime; + inc_refcount = true; + break; + case 'R': // service reference string + tmp = service; + inc_refcount = true; + break; + case 'N': // service name + tmp = service_name; + inc_refcount = true; + } + if (!tmp) + { + tmp = Py_None; + inc_refcount = true; + } + if (inc_refcount) + Py_INCREF(tmp); + PyTuple_SET_ITEM(tuple, pos++, tmp); + } +} + +PyObject *handleEvent(ePtr &ptr, PyObject *dest_list, char* argstring, int argcount, PyObject *service, PyObject *nowTime, PyObject *service_name, PyObject *convertFunc, PyObject *convertFuncArgs) +{ + if (convertFunc) + { + fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name); + PyObject *result = PyObject_CallObject(convertFunc, convertFuncArgs); + if (result == NULL) + { + if (service_name) + Py_DECREF(service_name); + if (nowTime) + Py_DECREF(nowTime); + Py_DECREF(convertFuncArgs); + Py_DECREF(dest_list); + return result; + } + PyList_Append(dest_list, result); + Py_DECREF(result); + } + else + { + PyObject *tuple = PyTuple_New(argcount); + fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name); + PyList_Append(dest_list, tuple); + Py_DECREF(tuple); + } + return 0; +} + +// here we get a list with tuples +// first tuple entry is the servicereference +// the second is the type of query (0 = time, 1 = event_id) +// the third +// when type is eventid it is the event_id +// when type is time then it is the start_time ( 0 for now_time ) +// the fourth is the end_time .. ( optional ) + +/* argv is a python string + I = Event Id + B = Event Begin Time + D = Event Duration + T = Event Title + S = Event Short Description + E = Event Extended Description + C = Current Time + R = Service Reference + N = Service Name +*/ + +PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc) +{ + PyObject *convertFuncArgs=NULL; + int argcount=0; + char *argstring=NULL; + if (!PyList_Check(list)) + { + PyErr_SetString(PyExc_StandardError, + "type error"); + eDebug("no list"); + return NULL; + } + int listIt=0; + int listSize=PyList_Size(list); + if (!listSize) + { + PyErr_SetString(PyExc_StandardError, + "not params given"); + eDebug("not params given"); + return NULL; + } + else + { + PyObject *argv=PyList_GET_ITEM(list, 0); // borrowed reference! + if (PyString_Check(argv)) + { + argstring = PyString_AS_STRING(argv); + ++listIt; + } + else + argstring = "I"; // just event id as default + argcount = strlen(argstring); +// eDebug("have %d args('%s')", argcount, argstring); + } + if (convertFunc) + { + if (!PyCallable_Check(convertFunc)) + { + PyErr_SetString(PyExc_StandardError, + "convertFunc must be callable"); + eDebug("convertFunc is not callable"); + return NULL; + } + convertFuncArgs = PyTuple_New(argcount); + } + + PyObject *nowTime = strchr(argstring, 'C') ? + PyLong_FromLong(time(0)+eDVBLocalTimeHandler::getInstance()->difference()) : + NULL; + + bool must_get_service_name = strchr(argstring, 'N') ? true : false; + + // create dest list + PyObject *dest_list=PyList_New(0); + while(listSize > listIt) + { + PyObject *item=PyList_GET_ITEM(list, listIt++); // borrowed reference! + if (PyTuple_Check(item)) + { + int type=0; + long event_id=-1; + time_t stime=-1; + int minutes=0; + int tupleSize=PyTuple_Size(item); + int tupleIt=0; + PyObject *service=NULL; + while(tupleSize > tupleIt) // parse query args + { + PyObject *entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference! + switch(tupleIt++) + { + case 0: + { + if (!PyString_Check(entry)) + { + eDebug("tuple entry 0 is no a string"); + continue; + } + service = entry; + break; + } + case 1: + type=PyInt_AsLong(entry); + if (type < -1 || type > 2) + { + eDebug("unknown type %d", type); + continue; + } + break; + case 2: + event_id=stime=PyInt_AsLong(entry); + break; + case 3: + minutes=PyInt_AsLong(entry); + break; + default: + eDebug("unneeded extra argument"); + break; + } + } + eServiceReference ref(PyString_AS_STRING(service)); + if (ref.type != eServiceReference::idDVB) + { + eDebug("service reference for epg query is not valid"); + continue; + } + PyObject *service_name=NULL; + if (must_get_service_name) + { + ePtr sptr; + eServiceCenterPtr service_center; + eServiceCenter::getPrivInstance(service_center); + if (service_center) + { + service_center->info(ref, sptr); + if (sptr) + { + std::string name; + sptr->getName(ref, name); + if (name.length()) + service_name = PyString_FromString(name.c_str()); + } + } + if (!service_name) + service_name = PyString_FromString(""); + } + if (minutes) + { + Lock(); + if (!startTimeQuery(ref, stime, minutes)) + { + ePtr ptr; + while (!getNextTimeEntry(ptr)) + { + PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs); + if (ret) + return ret; + } + } + Unlock(); + } + else + { + ePtr ptr; + if (stime) + { + if (type == 2) + lookupEventId(ref, event_id, ptr); + else + lookupEventTime(ref, stime, ptr, type); + } + PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs); + if (ret) + return ret; + } + if (service_name) + Py_DECREF(service_name); + } + } + if (convertFuncArgs) + Py_DECREF(convertFuncArgs); + if (nowTime) + Py_DECREF(nowTime); + return dest_list; +} + + + +