1 #include <lib/dvb/epgcache.h>
2 #include <lib/dvb/dvb.h>
7 #include <unistd.h> // for usleep
8 #include <sys/vfs.h> // for statfs
10 #include <lib/base/eerror.h>
12 int eventData::CacheSize=0;
14 eEPGCache* eEPGCache::instance;
15 pthread_mutex_t eEPGCache::cache_lock=
16 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
20 eEPGCache::eEPGCache()
21 :messages(this,1), back_messages(this,1) ,paused(0)
22 ,CleanTimer(this), zapTimer(this), abortTimer(this)
24 eDebug("[EPGC] Initialized EPGCache");
27 CONNECT(messages.recv_msg, eEPGCache::gotMessage);
28 CONNECT(back_messages.recv_msg, eEPGCache::gotBackMessage);
29 // CONNECT(eDVB::getInstance()->switchedService, eEPGCache::enterService);
30 // CONNECT(eDVB::getInstance()->leaveService, eEPGCache::leaveService);
31 CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
32 CONNECT(zapTimer.timeout, eEPGCache::startEPG);
33 CONNECT(CleanTimer.timeout, eEPGCache::cleanLoop);
34 CONNECT(abortTimer.timeout, eEPGCache::abortNonAvail);
38 void eEPGCache::timeUpdated()
40 if ( !thread_running() )
42 eDebug("[EPGC] time updated.. start EPG Mainloop");
46 messages.send(Message(Message::timeChanged));
49 int eEPGCache::sectionRead(const __u8 *data, int source)
51 eit_t *eit = (eit_t*) data;
53 int len=HILO(eit->section_length)-1;//+3-4;
59 // This fixed the EPG on the Multichoice irdeto systems
60 // the EIT packet is non-compliant.. their EIT packet stinks
61 if ( data[ptr-1] < 0x40 )
64 uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
65 eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
69 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);
70 // FIXME !!! TIME CORRECTION !
71 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
73 if ( TM != 3599 && TM > -1)
90 // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
91 // oder eine durch [] erzeugte
92 std::pair<eventMap,timeMap> &servicemap = eventDB[service];
93 eventMap::iterator prevEventIt = servicemap.first.end();
94 timeMap::iterator prevTimeIt = servicemap.second.end();
98 eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
100 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
102 eit_event->start_time_1,
103 eit_event->start_time_2,
104 eit_event->start_time_3,
105 eit_event->start_time_4,
106 eit_event->start_time_5);
111 if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
114 if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ ) // old events should not be cached
116 __u16 event_id = HILO(eit_event->event_id);
117 // eDebug("event_id is %d sid is %04x", event_id, service.sid);
120 int ev_erase_count = 0;
121 int tm_erase_count = 0;
123 // search in eventmap
124 eventMap::iterator ev_it =
125 servicemap.first.find(event_id);
127 // entry with this event_id is already exist ?
128 if ( ev_it != servicemap.first.end() )
130 if ( source > ev_it->second->type ) // update needed ?
131 goto next; // when not.. the skip this entry
132 // search this event in timemap
133 timeMap::iterator tm_it_tmp =
134 servicemap.second.find(ev_it->second->getStartTime());
136 if ( tm_it_tmp != servicemap.second.end() )
138 if ( tm_it_tmp->first == TM ) // correct eventData
141 delete ev_it->second;
142 evt = new eventData(eit_event, eit_event_size, source);
144 tm_it_tmp->second=evt;
150 // delete the found record from timemap
151 servicemap.second.erase(tm_it_tmp);
152 prevTimeIt=servicemap.second.end();
157 // search in timemap, for check of a case if new time has coincided with time of other event
158 // or event was is not found in eventmap
159 timeMap::iterator tm_it =
160 servicemap.second.find(TM);
162 if ( tm_it != servicemap.second.end() )
165 // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
167 if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ?
168 goto next; // when not.. the skip this entry
171 // search this time in eventmap
172 eventMap::iterator ev_it_tmp =
173 servicemap.first.find(tm_it->second->getEventID());
175 if ( ev_it_tmp != servicemap.first.end() )
178 // delete the found record from eventmap
179 servicemap.first.erase(ev_it_tmp);
180 prevEventIt=servicemap.first.end();
184 evt = new eventData(eit_event, eit_event_size, source);
186 bool consistencyCheck=true;
188 if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
191 delete ev_it->second;
192 delete tm_it->second;
196 else if (ev_erase_count == 0 && tm_erase_count > 0)
199 delete ev_it->second;
200 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
203 else if (ev_erase_count > 0 && tm_erase_count == 0)
206 delete tm_it->second;
207 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
210 else // added new eventData
213 consistencyCheck=false;
215 prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
216 prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
219 if ( consistencyCheck )
221 if ( tm_it->second != evt || ev_it->second != evt )
222 eFatal("tm_it->second != ev_it->second");
223 else if ( tm_it->second->getStartTime() != tm_it->first )
224 eFatal("event start_time(%d) non equal timemap key(%d)",
225 tm_it->second->getStartTime(), tm_it->first );
226 else if ( tm_it->first != TM )
227 eFatal("timemap key(%d) non equal TM(%d)",
229 else if ( ev_it->second->getEventID() != ev_it->first )
230 eFatal("event_id (%d) non equal event_map key(%d)",
231 ev_it->second->getEventID(), ev_it->first);
232 else if ( ev_it->first != event_id )
233 eFatal("eventmap key(%d) non equal event_id(%d)",
234 ev_it->first, event_id );
240 if ( servicemap.first.size() != servicemap.second.size() )
242 FILE *f = fopen("/hdd/event_map.txt", "w+");
244 for (eventMap::iterator it(servicemap.first.begin())
245 ; it != servicemap.first.end(); ++it )
246 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
247 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
249 f = fopen("/hdd/time_map.txt", "w+");
251 for (timeMap::iterator it(servicemap.second.begin())
252 ; it != servicemap.second.end(); ++it )
253 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
254 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
257 eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d",
258 service.sid, service.tsid, service.onid,
259 servicemap.first.size(), servicemap.second.size() );
262 ptr += eit_event_size;
263 eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
266 tmpMap::iterator it = temp.find( service );
267 if ( it != temp.end() )
269 if ( source > it->second.second )
271 it->second.first=now;
272 it->second.second=source;
276 temp[service] = std::pair< time_t, int> (now, source);
283 bool eEPGCache::finishEPG()
285 if (!isRunning) // epg ready
287 eDebug("[EPGC] stop caching events");
288 zapTimer.start(UPDATE_INTERVAL, 1);
289 eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
291 singleLock l(cache_lock);
292 tmpMap::iterator It = temp.begin();
295 while (It != temp.end())
297 // eDebug("sid = %02x, onid = %02x, type %d", It->first.sid, It->first.onid, It->second.second );
298 if ( It->second.second == SCHEDULE
299 || ( It->second.second == NOWNEXT && !(haveData&1) )
302 // eDebug("ADD to last updated Map");
303 serviceLastUpdated[It->first]=It->second.first;
305 if ( eventDB.find( It->first ) == eventDB.end() )
307 // eDebug("REMOVE from update Map");
313 if (!eventDB[current_service].first.empty())
314 /*emit*/ EPGAvail(1);
316 /*emit*/ EPGUpdated();
323 void eEPGCache::flushEPG(const uniqueEPGKey & s)
325 eDebug("[EPGC] flushEPG %d", (int)(bool)s);
327 if (s) // clear only this service
329 eventCache::iterator it = eventDB.find(s);
330 if ( it != eventDB.end() )
332 eventMap &evMap = it->second.first;
333 timeMap &tmMap = it->second.second;
335 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
339 updateMap::iterator u = serviceLastUpdated.find(s);
340 if ( u != serviceLastUpdated.end() )
341 serviceLastUpdated.erase(u);
345 else // clear complete EPG Cache
347 for (eventCache::iterator it(eventDB.begin());
348 it != eventDB.end(); ++it)
350 eventMap &evMap = it->second.first;
351 timeMap &tmMap = it->second.second;
352 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
357 serviceLastUpdated.clear();
361 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
365 void eEPGCache::cleanLoop()
367 singleLock s(cache_lock);
370 CleanTimer.start(5000,true);
371 eDebug("[EPGC] schedule cleanloop");
374 if (!eventDB.empty() && !paused )
376 eDebug("[EPGC] start cleanloop");
377 const eit_event_struct* cur_event;
380 // FIXME !!! TIME_CORRECTION
381 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
383 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
385 for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
387 cur_event = (*It->second).get();
388 duration = fromBCD( cur_event->duration_1)*3600 + fromBCD(cur_event->duration_2)*60 + fromBCD(cur_event->duration_3);
390 if ( now > (It->first+duration) ) // outdated normal entry (nvod references to)
392 // remove entry from eventMap
393 eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
394 if ( b != DBIt->second.first.end() )
396 // release Heap Memory for this entry (new ....)
397 // eDebug("[EPGC] delete old event (evmap)");
398 DBIt->second.first.erase(b);
401 // remove entry from timeMap
402 // eDebug("[EPGC] release heap mem");
404 DBIt->second.second.erase(It++);
405 // eDebug("[EPGC] delete old event (timeMap)");
407 // add this (changed) service to temp map...
408 if ( temp.find(DBIt->first) == temp.end() )
409 temp[DBIt->first]=std::pair<time_t, int>(now, NOWNEXT);
414 if ( DBIt->second.second.size() < 2 )
415 // less than two events for this service in cache..
417 updateMap::iterator u = serviceLastUpdated.find(DBIt->first);
418 if ( u != serviceLastUpdated.end() )
420 // remove from lastupdated map..
421 serviceLastUpdated.erase(u);
423 if ( DBIt->first == current_service )
425 // immediate .. after leave cleanloop
426 // update epgdata for this service
427 zapTimer.start(0,true);
434 /*emit*/ EPGUpdated();
436 eDebug("[EPGC] stop cleanloop");
437 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
439 CleanTimer.start(CLEAN_INTERVAL,true);
442 eEPGCache::~eEPGCache()
444 messages.send(Message::quit);
445 kill(); // waiting for thread shutdown
447 for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
448 for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
453 Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, int event_id, bool plain)
455 singleLock s(cache_lock);
456 uniqueEPGKey key( service );
458 eventCache::iterator It = eventDB.find( key );
459 if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
461 eventMap::iterator i( It->second.first.find( event_id ));
462 if ( i != It->second.first.end() )
464 if ( service.getServiceType() == 4 ) // nvod ref
465 return lookupEvent( service, i->second->getStartTime(), plain );
467 // get plain data... not in Event Format !!!
468 // before use .. cast it to eit_event_struct*
469 return (Event*) i->second->get();
471 return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid*/ );
474 eDebug("event %04x not found in epgcache", event_id);
479 Event *eEPGCache::lookupEvent(const eServiceReferenceDVB &service, time_t t, bool plain )
480 // if t == 0 we search the current event...
482 singleLock s(cache_lock);
483 uniqueEPGKey key(service);
485 // check if EPG for this service is ready...
486 eventCache::iterator It = eventDB.find( key );
487 if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
490 t = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
492 timeMap::iterator i = It->second.second.lower_bound(t);
493 if ( i != It->second.second.end() )
496 if ( i != It->second.second.end() )
498 const eit_event_struct* eit_event = i->second->get();
499 int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
500 if ( t <= i->first+duration )
503 // get plain data... not in Event Format !!!
504 // before use .. cast it to eit_event_struct*
505 return (Event*) i->second->get();
506 return new Event( (uint8_t*)i->second->get() /*, (It->first.tsid<<16)|It->first.onid */ );
511 for ( eventMap::iterator i( It->second.first.begin() ); i != It->second.first.end(); i++)
513 const eit_event_struct* eit_event = i->second->get();
514 int duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
515 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);
516 if ( t >= begTime && t <= begTime+duration) // then we have found
519 // get plain data... not in Event Format !!!
520 // before use .. cast it to eit_event_struct*
521 return (Event*) i->second->get();
522 return new Event( (uint8_t*)i->second->get()/*, (It->first.tsid<<16)|It->first.onid*/ );
529 void eEPGCache::pauseEPG()
534 eDebug("[EPGC] paused]");
539 void eEPGCache::restartEPG()
544 eDebug("[EPGC] restarted");
549 startEPG(); // updateEPG
555 void eEPGCache::startEPG()
557 if (paused) // called from the updateTimer during pause...
562 if (eDVBLocalTimeHandler::getInstance()->ready())
567 eDebug("[EPGC] start caching events");
571 eDVBSectionFilterMask mask;
572 memset(&mask, 0, sizeof(mask));
574 mask.flags = eDVBSectionFilterMask::rfCRC;
578 m_NowNextReader->start(mask);
583 m_ScheduleReader->start(mask);
588 m_ScheduleOtherReader->start(mask);
591 abortTimer.start(5000,true);
595 eDebug("[EPGC] wait for clock update");
596 zapTimer.start(1000, 1); // restart Timer
600 void eEPGCache::abortNonAvail()
604 if ( !(haveData&2) && (isRunning&2) )
606 eDebug("[EPGC] abort non avail nownext reading");
608 if ( m_NowNextReader )
609 m_NowNextReader->stop();
611 if ( !(haveData&1) && (isRunning&1) )
613 eDebug("[EPGC] abort non avail schedule reading");
615 m_ScheduleReader->stop();
617 if ( !(haveData&4) && (isRunning&4) )
619 eDebug("[EPGC] abort non avail schedule_other reading");
621 m_ScheduleOtherReader->stop();
623 abortTimer.start(20000, true);
628 void eEPGCache::startCache(const eServiceReferenceDVB& ref)
630 if ( m_currentChannel )
633 leaveChannel(m_currentChannel);
637 ref.getChannelID( chid );
638 ePtr<eDVBResourceManager> res_mgr;
639 if ( eDVBResourceManager::getInstance( res_mgr ) )
640 eDebug("[eEPGCache] no res manager!!");
643 ePtr<iDVBDemux> demux;
644 res_mgr->allocateChannel(chid, m_currentChannel);
645 if ( m_currentChannel->getDemux(demux) )
647 eDebug("[eEPGCache] no demux!!");
653 m_NowNextReader = new eDVBSectionReader( demux, this, res );
656 eDebug("[eEPGCache] couldnt initialize nownext reader!!");
659 m_NowNextReader->connectRead(slot(*this, &eEPGCache::readNowNextData), m_NowNextConn);
660 m_ScheduleReader = new eDVBSectionReader( demux, this, res );
663 eDebug("[eEPGCache] couldnt initialize schedule reader!!");
666 m_ScheduleReader->connectRead(slot(*this, &eEPGCache::readScheduleData), m_ScheduleConn);
667 m_ScheduleOtherReader = new eDVBSectionReader( demux, this, res );
670 eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
673 m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::readScheduleOtherData), m_ScheduleOtherConn);
674 messages.send(Message(Message::startService, ref));
675 // -> gotMessage -> changedService
680 m_ScheduleOtherReader=0;
681 m_ScheduleOtherConn=0;
692 void eEPGCache::leaveChannel(iDVBChannel * chan)
694 if ( chan && chan == m_currentChannel )
696 messages.send(Message(Message::leaveChannel, chan));
697 // -> gotMessage -> abortEPG
701 void eEPGCache::changedService(const uniqueEPGKey &service)
703 current_service = service;
704 updateMap::iterator It = serviceLastUpdated.find( current_service );
708 // check if this is a subservice and this is only a dbox2
709 // then we dont start epgcache on subservice change..
712 // if ( !err || err == -ENOCASYS )
714 update = ( It != serviceLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
716 if (update < ZAP_DELAY)
719 zapTimer.start(update, 1);
721 eDebug("[EPGC] next update in %i min", update/60000);
722 else if (update >= 1000)
723 eDebug("[EPGC] next update in %i sec", update/1000);
727 bool empty=eventDB[current_service].first.empty();
732 eDebug("[EPGC] yet cached");
733 /*emit*/ EPGAvail(1);
737 eDebug("[EPGC] not cached yet");
738 /*emit*/ EPGAvail(0);
742 void eEPGCache::abortEPG()
751 if ( m_ScheduleReader )
752 m_ScheduleReader->stop();
757 if ( m_NowNextReader )
758 m_NowNextReader->stop();
763 if ( m_ScheduleOtherReader )
764 m_ScheduleOtherReader->stop();
766 eDebug("[EPGC] abort caching events !!");
773 void eEPGCache::gotMessage( const Message &msg )
778 flushEPG(msg.service);
780 case Message::startService:
781 changedService(msg.service);
783 case Message::leaveChannel:
785 back_messages.send(Message(Message::leaveChannelFinished));
790 case Message::restart:
796 case Message::timeChanged:
800 eDebug("unhandled EPGCache Message!!");
805 void eEPGCache::gotBackMessage( const Message &msg )
809 case Message::leaveChannelFinished:
810 m_ScheduleOtherReader=0;
811 m_ScheduleOtherConn=0;
817 eDebug("[eEPGC] channel leaved");
820 startCache(next_service);
821 next_service = eServiceReferenceDVB();
825 eDebug("unhandled EPGCache BackMessage!!");
830 void eEPGCache::thread()
839 void eEPGCache::load()
841 FILE *f = fopen("/hdd/epg.dat", "r");
844 unsigned char md5_saved[16];
845 unsigned char md5[16];
849 if (!md5_file("/hdd/epg.dat", 1, md5))
851 FILE *f = fopen("/hdd/epg.dat.md5", "r");
854 fread( md5_saved, 16, 1, f);
856 if ( !memcmp(md5_saved, md5, 16) )
862 fread( &size, sizeof(int), 1, f);
869 fread( &key, sizeof(uniqueEPGKey), 1, f);
870 fread( &size, sizeof(int), 1, f);
876 fread( &type, sizeof(int), 1, f);
877 fread( &len, sizeof(int), 1, f);
878 event = new eventData(0, len, type);
879 fread( event->EITdata, len, 1, f);
880 evMap[ event->getEventID() ]=event;
881 tmMap[ event->getStartTime() ]=event;
884 eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
886 eDebug("%d events read from /hdd/epg.dat.md5", cnt);
892 void eEPGCache::save()
896 if (statfs("/hdd", &s)<0)
904 // prevent writes to builtin flash
905 if ( tmp < 1024*1024*50 ) // storage size < 50MB
908 // check for enough free space on storage
911 if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
914 FILE *f = fopen("/hdd/epg.dat", "w");
918 int size = eventDB.size();
919 fwrite( &size, sizeof(int), 1, f );
920 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
922 timeMap &timemap = service_it->second.second;
923 fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
924 size = timemap.size();
925 fwrite( &size, sizeof(int), 1, f);
926 for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
928 int len = time_it->second->ByteSize;
929 fwrite( &time_it->second->type, sizeof(int), 1, f );
930 fwrite( &len, sizeof(int), 1, f);
931 fwrite( time_it->second->EITdata, len, 1, f);
935 eDebug("%d events written to /hdd/epg.dat", cnt);
937 unsigned char md5[16];
938 if (!md5_file("/hdd/epg.dat", 1, md5))
940 FILE *f = fopen("/hdd/epg.dat.md5", "w");
943 fwrite( md5, 16, 1, f);
950 RESULT eEPGCache::getInstance(ePtr<eEPGCache> &ptr)