diff options
| author | Andreas Monzner <andreas.monzner@multimedia-labs.de> | 2005-07-04 17:49:04 +0000 |
|---|---|---|
| committer | Andreas Monzner <andreas.monzner@multimedia-labs.de> | 2005-07-04 17:49:04 +0000 |
| commit | 20f69c200ec5703e958a6b95abfcfd5a108e5939 (patch) | |
| tree | a7f25f70a49c278048cfca2559e4682ba92211fa /lib/dvb/epgcache.cpp | |
| parent | a8310a1a7345577916560e789cdb8c1712e620a9 (diff) | |
| download | enigma2-20f69c200ec5703e958a6b95abfcfd5a108e5939.tar.gz enigma2-20f69c200ec5703e958a6b95abfcfd5a108e5939.zip | |
add epgcache
Diffstat (limited to 'lib/dvb/epgcache.cpp')
| -rw-r--r-- | lib/dvb/epgcache.cpp | 957 |
1 files changed, 957 insertions, 0 deletions
diff --git a/lib/dvb/epgcache.cpp b/lib/dvb/epgcache.cpp new file mode 100644 index 00000000..41635b03 --- /dev/null +++ b/lib/dvb/epgcache.cpp @@ -0,0 +1,957 @@ +#include <lib/dvb/epgcache.h> +#include <lib/dvb/dvb.h> + +#undef EPG_DEBUG + +#include <time.h> +#include <unistd.h> // for usleep +#include <sys/vfs.h> // for statfs +#include <libmd5sum.h> +#include <lib/base/eerror.h> + +int eventData::CacheSize=0; + +eEPGCache* eEPGCache::instance; +pthread_mutex_t eEPGCache::cache_lock= + PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + +DEFINE_REF(eEPGCache) + +eEPGCache::eEPGCache() + :messages(this,1), back_messages(this,1) ,paused(0) + ,CleanTimer(this), zapTimer(this), abortTimer(this) +{ + eDebug("[EPGC] Initialized EPGCache"); + isRunning=0; + + CONNECT(messages.recv_msg, eEPGCache::gotMessage); + CONNECT(back_messages.recv_msg, eEPGCache::gotBackMessage); +// CONNECT(eDVB::getInstance()->switchedService, eEPGCache::enterService); +// CONNECT(eDVB::getInstance()->leaveService, eEPGCache::leaveService); + CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated); + CONNECT(zapTimer.timeout, eEPGCache::startEPG); + CONNECT(CleanTimer.timeout, eEPGCache::cleanLoop); + CONNECT(abortTimer.timeout, eEPGCache::abortNonAvail); + instance=this; +} + +void eEPGCache::timeUpdated() +{ + if ( !thread_running() ) + { + eDebug("[EPGC] time updated.. start EPG Mainloop"); + run(); + } + else + messages.send(Message(Message::timeChanged)); +} + +int eEPGCache::sectionRead(const __u8 *data, int source) +{ + eit_t *eit = (eit_t*) data; + + int len=HILO(eit->section_length)-1;//+3-4; + int ptr=EIT_SIZE; + if ( ptr >= len ) + return 0; + + // + // This fixed the EPG on the Multichoice irdeto systems + // the EIT packet is non-compliant.. their EIT packet stinks + if ( data[ptr-1] < 0x40 ) + --ptr; + + uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) ); + eit_event_struct* eit_event = (eit_event_struct*) (data+ptr); + int eit_event_size; + int duration; + + time_t TM = parseDVBtime( eit_event->start_time_1, eit_event->start_time_2, eit_event->start_time_3, eit_event->start_time_4, eit_event->start_time_5); +// FIXME !!! TIME CORRECTION ! + time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + + if ( TM != 3599 && TM > -1) + { + switch(source) + { + case NOWNEXT: + haveData |= 2; + break; + case SCHEDULE: + haveData |= 1; + break; + case SCHEDULE_OTHER: + haveData |= 4; + break; + } + } + + Lock(); + // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene.. + // oder eine durch [] erzeugte + std::pair<eventMap,timeMap> &servicemap = eventDB[service]; + eventMap::iterator prevEventIt = servicemap.first.end(); + timeMap::iterator prevTimeIt = servicemap.second.end(); + + while (ptr<len) + { + eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE; + + duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3); + TM = parseDVBtime( + eit_event->start_time_1, + eit_event->start_time_2, + eit_event->start_time_3, + eit_event->start_time_4, + eit_event->start_time_5); + + if ( TM == 3599 ) + goto next; + + if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) ) + goto next; + + if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ ) // old events should not be cached + { + __u16 event_id = HILO(eit_event->event_id); +// eDebug("event_id is %d sid is %04x", event_id, service.sid); + + eventData *evt = 0; + int ev_erase_count = 0; + int tm_erase_count = 0; + +// search in eventmap + eventMap::iterator ev_it = + servicemap.first.find(event_id); + + // entry with this event_id is already exist ? + if ( ev_it != servicemap.first.end() ) + { + if ( source > ev_it->second->type ) // update needed ? + goto next; // when not.. the skip this entry +// search this event in timemap + timeMap::iterator tm_it_tmp = + servicemap.second.find(ev_it->second->getStartTime()); + + if ( tm_it_tmp != servicemap.second.end() ) + { + if ( tm_it_tmp->first == TM ) // correct eventData + { + // exempt memory + delete ev_it->second; + evt = new eventData(eit_event, eit_event_size, source); + ev_it->second=evt; + tm_it_tmp->second=evt; + goto next; + } + else + { + tm_erase_count++; + // delete the found record from timemap + servicemap.second.erase(tm_it_tmp); + prevTimeIt=servicemap.second.end(); + } + } + } + +// search in timemap, for check of a case if new time has coincided with time of other event +// or event was is not found in eventmap + timeMap::iterator tm_it = + servicemap.second.find(TM); + + if ( tm_it != servicemap.second.end() ) + { + +// i think, if event is not found on eventmap, but found on timemap updating nevertheless demands +#if 0 + if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ? + goto next; // when not.. the skip this entry +#endif + +// search this time in eventmap + eventMap::iterator ev_it_tmp = + servicemap.first.find(tm_it->second->getEventID()); + + if ( ev_it_tmp != servicemap.first.end() ) + { + ev_erase_count++; + // delete the found record from eventmap + servicemap.first.erase(ev_it_tmp); + prevEventIt=servicemap.first.end(); + } + } + + evt = new eventData(eit_event, eit_event_size, source); +#if EPG_DEBUG + bool consistencyCheck=true; +#endif + if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed + { + // exempt memory + delete ev_it->second; + delete tm_it->second; + ev_it->second=evt; + tm_it->second=evt; + } + else if (ev_erase_count == 0 && tm_erase_count > 0) + { + // exempt memory + delete ev_it->second; + tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) ); + ev_it->second=evt; + } + else if (ev_erase_count > 0 && tm_erase_count == 0) + { + // exempt memory + delete tm_it->second; + ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) ); + tm_it->second=evt; + } + else // added new eventData + { +#if EPG_DEBUG + consistencyCheck=false; +#endif + prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) ); + prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) ); + } +#if EPG_DEBUG + if ( consistencyCheck ) + { + if ( tm_it->second != evt || ev_it->second != evt ) + eFatal("tm_it->second != ev_it->second"); + else if ( tm_it->second->getStartTime() != tm_it->first ) + eFatal("event start_time(%d) non equal timemap key(%d)", + tm_it->second->getStartTime(), tm_it->first ); + else if ( tm_it->first != TM ) + eFatal("timemap key(%d) non equal TM(%d)", + tm_it->first, TM); + else if ( ev_it->second->getEventID() != ev_it->first ) + eFatal("event_id (%d) non equal event_map key(%d)", + ev_it->second->getEventID(), ev_it->first); + else if ( ev_it->first != event_id ) + eFatal("eventmap key(%d) non equal event_id(%d)", + ev_it->first, event_id ); + } +#endif + } +next: +#if EPG_DEBUG + if ( servicemap.first.size() != servicemap.second.size() ) + { + FILE *f = fopen("/hdd/event_map.txt", "w+"); + int i=0; + for (eventMap::iterator it(servicemap.first.begin()) + ; it != servicemap.first.end(); ++it ) + fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", + i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second ); + fclose(f); + f = fopen("/hdd/time_map.txt", "w+"); + i=0; + for (timeMap::iterator it(servicemap.second.begin()) + ; it != servicemap.second.end(); ++it ) + fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n", + i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second ); + fclose(f); + + eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d", + service.sid, service.tsid, service.onid, + servicemap.first.size(), servicemap.second.size() ); + } +#endif + ptr += eit_event_size; + eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size); + } + + tmpMap::iterator it = temp.find( service ); + if ( it != temp.end() ) + { + if ( source > it->second.second ) + { + it->second.first=now; + it->second.second=source; + } + } + else + temp[service] = std::pair< time_t, int> (now, source); + + Unlock(); + + return 0; +} + +bool eEPGCache::finishEPG() +{ + if (!isRunning) // epg ready + { + eDebug("[EPGC] stop caching events"); + zapTimer.start(UPDATE_INTERVAL, 1); + eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000); + + singleLock l(cache_lock); + tmpMap::iterator It = temp.begin(); + abortTimer.stop(); + + while (It != temp.end()) + { +// eDebug("sid = %02x, onid = %02x, type %d", It->first.sid, It->first.onid, It->second.second ); + if ( It->second.second == SCHEDULE + || ( It->second.second == NOWNEXT && !(haveData&1) ) + ) + { +// eDebug("ADD to last updated Map"); + serviceLastUpdated[It->first]=It->second.first; + } + if ( eventDB.find( It->first ) == eventDB.end() ) + { +// eDebug("REMOVE from update Map"); + temp.erase(It++); + } + else + It++; + } + if (!eventDB[current_service].first.empty()) + /*emit*/ EPGAvail(1); + + /*emit*/ EPGUpdated(); + + return true; + } + return false; +} + +void eEPGCache::flushEPG(const uniqueEPGKey & s) +{ + eDebug("[EPGC] flushEPG %d", (int)(bool)s); + Lock(); + if (s) // clear only this service + { + eventCache::iterator it = eventDB.find(s); + if ( it != eventDB.end() ) + { + eventMap &evMap = it->second.first; + timeMap &tmMap = it->second.second; + tmMap.clear(); + for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i) + delete i->second; + evMap.clear(); + eventDB.erase(it); + updateMap::iterator u = serviceLastUpdated.find(s); + if ( u != serviceLastUpdated.end() ) + serviceLastUpdated.erase(u); + startEPG(); + } + } + else // clear complete EPG Cache + { + for (eventCache::iterator it(eventDB.begin()); + it != eventDB.end(); ++it) + { + eventMap &evMap = it->second.first; + timeMap &tmMap = it->second.second; + for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i) + delete i->second; + evMap.clear(); + tmMap.clear(); + } + serviceLastUpdated.clear(); + eventDB.clear(); + startEPG(); + } + eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize); + Unlock(); +} + +void eEPGCache::cleanLoop() +{ + singleLock s(cache_lock); + if ( isRunning ) + { + CleanTimer.start(5000,true); + eDebug("[EPGC] schedule cleanloop"); + return; + } + if (!eventDB.empty() && !paused ) + { + eDebug("[EPGC] start cleanloop"); + const eit_event_struct* cur_event; + int duration; + +// FIXME !!! TIME_CORRECTION + time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + + for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++) + { + for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;) + { + cur_event = (*It->second).get(); + duration = fromBCD( cur_event->duration_1)*3600 + fromBCD(cur_event->duration_2)*60 + fromBCD(cur_event->duration_3); + + if ( now > (It->first+duration) ) // outdated normal entry (nvod references to) + { + // remove entry from eventMap + eventMap::iterator b(DBIt->second.first.find(It->second->getEventID())); + if ( b != DBIt->second.first.end() ) + { + // release Heap Memory for this entry (new ....) +// eDebug("[EPGC] delete old event (evmap)"); + DBIt->second.first.erase(b); + } + + // remove entry from timeMap +// eDebug("[EPGC] release heap mem"); + delete It->second; + DBIt->second.second.erase(It++); +// eDebug("[EPGC] delete old event (timeMap)"); + + // add this (changed) service to temp map... + if ( temp.find(DBIt->first) == temp.end() ) + temp[DBIt->first]=std::pair<time_t, int>(now, NOWNEXT); + } + else + ++It; + } + if ( DBIt->second.second.size() < 2 ) + // less than two events for this service in cache.. + { + updateMap::iterator u = serviceLastUpdated.find(DBIt->first); + if ( u != serviceLastUpdated.end() ) + { + // remove from lastupdated map.. + serviceLastUpdated.erase(u); + // current service? + if ( DBIt->first == current_service ) + { + // immediate .. after leave cleanloop + // update epgdata for this service + zapTimer.start(0,true); + } + } + } + } + + if (temp.size()) + /*emit*/ EPGUpdated(); + + eDebug("[EPGC] stop cleanloop"); + eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize); + } + CleanTimer.start(CLEAN_INTERVAL,true); +} + +eEPGCache::~eEPGCache() +{ + messages.send(Message::quit); + kill(); // waiting for thread shutdown + Lock(); + for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++) + for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++) + delete It->second; + Unlock(); +} + +Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, int event_id, bool plain) +{ + singleLock s(cache_lock); + uniqueEPGKey key( service ); + + eventCache::iterator It = eventDB.find( key ); + if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached? + { + eventMap::iterator i( It->second.first.find( event_id )); + if ( i != It->second.first.end() ) + { + if ( service.getServiceType() == 4 ) // nvod ref + return lookupEvent( service, i->second->getStartTime(), plain ); + else if ( plain ) + // get plain data... not in Event Format !!! + // before use .. cast it to eit_event_struct* + return (Event*) i->second->get(); + else + return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid*/ ); + } + else + eDebug("event %04x not found in epgcache", event_id); + } + return 0; +} + +Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, time_t t, bool plain ) +// if t == 0 we search the current event... +{ + singleLock s(cache_lock); + uniqueEPGKey key(service); + + // check if EPG for this service is ready... + eventCache::iterator It = eventDB.find( key ); + if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ? + { + if (!t) + t = time(0)+eDVBLocalTimeHandler::getInstance()->difference(); + + timeMap::iterator i = It->second.second.lower_bound(t); + if ( i != It->second.second.end() ) + { + i--; + if ( i != It->second.second.end() ) + { + const eit_event_struct* eit_event = i->second->get(); + int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3); + if ( t <= i->first+duration ) + { + if ( plain ) + // get plain data... not in Event Format !!! + // before use .. cast it to eit_event_struct* + return (Event*) i->second->get(); + return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid */ ); + } + } + } + + for ( eventMap::iterator i( It->second.first.begin() ); i != It->second.first.end(); i++) + { + const eit_event_struct* eit_event = i->second->get(); + int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3); + time_t begTime = parseDVBtime( eit_event->start_time_1, eit_event->start_time_2, eit_event->start_time_3, eit_event->start_time_4, eit_event->start_time_5); + if ( t >= begTime && t <= begTime+duration) // then we have found + { + if ( plain ) + // get plain data... not in Event Format !!! + // before use .. cast it to eit_event_struct* + return (Event*) i->second->get(); + return new Event( (uint8_t*)i->second->get()/*, (It->first.tsid<<16)|It->first.onid*/ ); + } + } + } + return 0; +} + +void eEPGCache::pauseEPG() +{ + if (!paused) + { + abortEPG(); + eDebug("[EPGC] paused]"); + paused=1; + } +} + +void eEPGCache::restartEPG() +{ + if (paused) + { + isRunning=0; + eDebug("[EPGC] restarted"); + paused--; + if (paused) + { + paused = 0; + startEPG(); // updateEPG + } + cleanLoop(); + } +} + +void eEPGCache::startEPG() +{ + if (paused) // called from the updateTimer during pause... + { + paused++; + return; + } + if (eDVBLocalTimeHandler::getInstance()->ready()) + { + Lock(); + temp.clear(); + Unlock(); + eDebug("[EPGC] start caching events"); + state=0; + haveData=0; + + eDVBSectionFilterMask mask; + memset(&mask, 0, sizeof(mask)); + mask.pid = 0x12; + mask.flags = eDVBSectionFilterMask::rfCRC; + + mask.data[0] = 0x4E; + mask.mask[0] = 0xFE; + m_NowNextReader->start(mask); + isRunning |= 1; + + mask.data[0] = 0x50; + mask.mask[0] = 0xF0; + m_ScheduleReader->start(mask); + isRunning |= 2; + + mask.data[0] = 0x60; + mask.mask[0] = 0xF0; + m_ScheduleOtherReader->start(mask); + isRunning |= 4; + + abortTimer.start(5000,true); + } + else + { + eDebug("[EPGC] wait for clock update"); + zapTimer.start(1000, 1); // restart Timer + } +} + +void eEPGCache::abortNonAvail() +{ + if (!state) + { + if ( !(haveData&2) && (isRunning&2) ) + { + eDebug("[EPGC] abort non avail nownext reading"); + isRunning &= ~2; + if ( m_NowNextReader ) + m_NowNextReader->stop(); + } + if ( !(haveData&1) && (isRunning&1) ) + { + eDebug("[EPGC] abort non avail schedule reading"); + isRunning &= ~1; + m_ScheduleReader->stop(); + } + if ( !(haveData&4) && (isRunning&4) ) + { + eDebug("[EPGC] abort non avail schedule_other reading"); + isRunning &= ~4; + m_ScheduleOtherReader->stop(); + } + abortTimer.start(20000, true); + } + ++state; +} + +void eEPGCache::startCache(const eServiceReferenceDVB& ref) +{ + if ( m_currentChannel ) + { + next_service = ref; + leaveChannel(m_currentChannel); + return; + } + eDVBChannelID chid; + ref.getChannelID( chid ); + ePtr<eDVBResourceManager> res_mgr; + if ( eDVBResourceManager::getInstance( res_mgr ) ) + eDebug("[eEPGCache] no res manager!!"); + else + { + ePtr<iDVBDemux> demux; + res_mgr->allocateChannel(chid, m_currentChannel); + if ( m_currentChannel->getDemux(demux) ) + { + eDebug("[eEPGCache] no demux!!"); + goto error4; + } + else + { + RESULT res; + m_NowNextReader = new eDVBSectionReader( demux, this, res ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize nownext reader!!"); + goto error3; + } + m_NowNextReader->connectRead(slot(*this, &eEPGCache::readNowNextData), m_NowNextConn); + m_ScheduleReader = new eDVBSectionReader( demux, this, res ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize schedule reader!!"); + goto error2; + } + m_ScheduleReader->connectRead(slot(*this, &eEPGCache::readScheduleData), m_ScheduleConn); + m_ScheduleOtherReader = new eDVBSectionReader( demux, this, res ); + if ( res ) + { + eDebug("[eEPGCache] couldnt initialize schedule other reader!!"); + goto error1; + } + m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::readScheduleOtherData), m_ScheduleOtherConn); + messages.send(Message(Message::startService, ref)); + // -> gotMessage -> changedService + } + } + return; +error1: + m_ScheduleOtherReader=0; + m_ScheduleOtherConn=0; +error2: + m_ScheduleReader=0; + m_ScheduleConn=0; +error3: + m_NowNextReader=0; + m_NowNextConn=0; +error4: + m_currentChannel=0; +} + +void eEPGCache::leaveChannel(iDVBChannel * chan) +{ + if ( chan && chan == m_currentChannel ) + { + messages.send(Message(Message::leaveChannel, chan)); + // -> gotMessage -> abortEPG + } +} + +void eEPGCache::changedService(const uniqueEPGKey &service) +{ + current_service = service; + updateMap::iterator It = serviceLastUpdated.find( current_service ); + + int update; + +// check if this is a subservice and this is only a dbox2 +// then we dont start epgcache on subservice change.. +// ever and ever.. + +// if ( !err || err == -ENOCASYS ) + { + update = ( It != serviceLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY ); + + if (update < ZAP_DELAY) + update = ZAP_DELAY; + + zapTimer.start(update, 1); + if (update >= 60000) + eDebug("[EPGC] next update in %i min", update/60000); + else if (update >= 1000) + eDebug("[EPGC] next update in %i sec", update/1000); + } + + Lock(); + bool empty=eventDB[current_service].first.empty(); + Unlock(); + + if (!empty) + { + eDebug("[EPGC] yet cached"); + /*emit*/ EPGAvail(1); + } + else + { + eDebug("[EPGC] not cached yet"); + /*emit*/ EPGAvail(0); + } +} + +void eEPGCache::abortEPG() +{ + abortTimer.stop(); + zapTimer.stop(); + if (isRunning) + { + if (isRunning & 1) + { + isRunning &= ~1; + if ( m_ScheduleReader ) + m_ScheduleReader->stop(); + } + if (isRunning & 2) + { + isRunning &= ~2; + if ( m_NowNextReader ) + m_NowNextReader->stop(); + } + if (isRunning & 4) + { + isRunning &= ~4; + if ( m_ScheduleOtherReader ) + m_ScheduleOtherReader->stop(); + } + eDebug("[EPGC] abort caching events !!"); + Lock(); + temp.clear(); + Unlock(); + } +} + +void eEPGCache::gotMessage( const Message &msg ) +{ + switch (msg.type) + { + case Message::flush: + flushEPG(msg.service); + break; + case Message::startService: + changedService(msg.service); + break; + case Message::leaveChannel: + abortEPG(); + back_messages.send(Message(Message::leaveChannelFinished)); + break; + case Message::pause: + pauseEPG(); + break; + case Message::restart: + restartEPG(); + break; + case Message::quit: + quit(0); + break; + case Message::timeChanged: + cleanLoop(); + break; + default: + eDebug("unhandled EPGCache Message!!"); + break; + } +} + +void eEPGCache::gotBackMessage( const Message &msg ) +{ + switch (msg.type) + { + case Message::leaveChannelFinished: + m_ScheduleOtherReader=0; + m_ScheduleOtherConn=0; + m_ScheduleReader=0; + m_ScheduleConn=0; + m_NowNextReader=0; + m_NowNextConn=0; + m_currentChannel=0; + eDebug("[eEPGC] channel leaved"); + if (next_service) + { + startCache(next_service); + next_service = eServiceReferenceDVB(); + } + break; + default: + eDebug("unhandled EPGCache BackMessage!!"); + break; + } +} + +void eEPGCache::thread() +{ + nice(4); + load(); + cleanLoop(); + exec(); + save(); +} + +void eEPGCache::load() +{ + FILE *f = fopen("/hdd/epg.dat", "r"); + if (f) + { + unsigned char md5_saved[16]; + unsigned char md5[16]; + int size=0; + int cnt=0; + bool md5ok=false; + if (!md5_file("/hdd/epg.dat", 1, md5)) + { + FILE *f = fopen("/hdd/epg.dat.md5", "r"); + if (f) + { + fread( md5_saved, 16, 1, f); + fclose(f); + if ( !memcmp(md5_saved, md5, 16) ) + md5ok=true; + } + } + if ( md5ok ) + { + fread( &size, sizeof(int), 1, f); + while(size--) + { + uniqueEPGKey key; + eventMap evMap; + timeMap tmMap; + int size=0; + fread( &key, sizeof(uniqueEPGKey), 1, f); + fread( &size, sizeof(int), 1, f); + while(size--) + { + int len=0; + int type=0; + eventData *event=0; + fread( &type, sizeof(int), 1, f); + fread( &len, sizeof(int), 1, f); + event = new eventData(0, len, type); + fread( event->EITdata, len, 1, f); + evMap[ event->getEventID() ]=event; + tmMap[ event->getStartTime() ]=event; + ++cnt; + } + eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap); + } + eDebug("%d events read from /hdd/epg.dat.md5", cnt); + } + fclose(f); + } +} + +void eEPGCache::save() +{ + struct statfs s; + off64_t tmp; + if (statfs("/hdd", &s)<0) + tmp=0; + else + { + tmp=s.f_blocks; + tmp*=s.f_bsize; + } + + // prevent writes to builtin flash + if ( tmp < 1024*1024*50 ) // storage size < 50MB + return; + + // check for enough free space on storage + tmp=s.f_bfree; + tmp*=s.f_bsize; + if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead + return; + + FILE *f = fopen("/hdd/epg.dat", "w"); + int cnt=0; + if ( f ) + { + int size = eventDB.size(); + fwrite( &size, sizeof(int), 1, f ); + for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it) + { + timeMap &timemap = service_it->second.second; + fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f); + size = timemap.size(); + fwrite( &size, sizeof(int), 1, f); + for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it) + { + int len = time_it->second->ByteSize; + fwrite( &time_it->second->type, sizeof(int), 1, f ); + fwrite( &len, sizeof(int), 1, f); + fwrite( time_it->second->EITdata, len, 1, f); + ++cnt; + } + } + eDebug("%d events written to /hdd/epg.dat", cnt); + fclose(f); + unsigned char md5[16]; + if (!md5_file("/hdd/epg.dat", 1, md5)) + { + FILE *f = fopen("/hdd/epg.dat.md5", "w"); + if (f) + { + fwrite( md5, 16, 1, f); + fclose(f); + } + } + } +} + +RESULT eEPGCache::getInstance(ePtr<eEPGCache> &ptr) +{ + ptr = instance; + if (!ptr) + return -1; + return 0; +} + |
