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
9 // #include <libmd5sum.h>
10 #include <lib/base/eerror.h>
13 int eventData::CacheSize=0;
14 descriptorMap eventData::descriptors;
15 __u8 eventData::data[4108];
16 extern const uint32_t crc32_table[256];
18 eventData::eventData(const eit_event_struct* e, int size, int type)
19 :ByteSize(size&0xFF), type(type&0xFF)
27 __u8 *data = (__u8*)e;
29 int descriptors_length = (data[ptr++]&0x0F) << 8;
30 descriptors_length |= data[ptr++];
31 while ( descriptors_length > 0 )
33 __u8 *descr = data+ptr;
34 int descr_len = descr[1]+2;
38 while(cnt++ < descr_len)
39 crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ data[ptr++]) & 0xFF];
41 descriptorMap::iterator it =
42 descriptors.find(crc);
43 if ( it == descriptors.end() )
46 __u8 *d = new __u8[descr_len];
47 memcpy(d, descr, descr_len);
48 descriptors[crc] = descriptorPair(1, d);
54 descriptors_length -= descr_len;
56 ByteSize = 12+((pdescr-descr)*4);
57 EITdata = new __u8[ByteSize];
59 memcpy(EITdata, (__u8*) e, 12);
60 memcpy(EITdata+12, descr, ByteSize-12);
63 const eit_event_struct* eventData::get() const
66 int tmp = ByteSize-12;
68 memcpy(data, EITdata, 12);
69 __u32 *p = (__u32*)(EITdata+12);
72 descriptorMap::iterator it =
73 descriptors.find(*p++);
74 if ( it != descriptors.end() )
76 int b = it->second.second[1]+2;
77 memcpy(data+pos, it->second.second, b );
83 return (const eit_event_struct*)data;
86 eventData::~eventData()
92 __u32 *d = (__u32*)(EITdata+12);
95 descriptorMap::iterator it =
96 descriptors.find(*d++);
97 if ( it != descriptors.end() )
99 descriptorPair &p = it->second;
100 if (!--p.first) // no more used descriptor
102 CacheSize -= it->second.second[1];
103 delete [] it->second.second; // free descriptor memory
104 descriptors.erase(it); // remove entry from descriptor map
113 void eventData::load(FILE *f)
119 fread(&size, sizeof(int), 1, f);
122 fread(&id, sizeof(__u32), 1, f);
123 fread(&p.first, sizeof(int), 1, f);
124 fread(header, 2, 1, f);
125 int bytes = header[1]+2;
126 p.second = new __u8[bytes];
127 p.second[0] = header[0];
128 p.second[1] = header[1];
129 fread(p.second+2, bytes-2, 1, f);
136 void eventData::save(FILE *f)
138 int size=descriptors.size();
139 descriptorMap::iterator it(descriptors.begin());
140 fwrite(&size, sizeof(int), 1, f);
143 fwrite(&it->first, sizeof(__u32), 1, f);
144 fwrite(&it->second.first, sizeof(int), 1, f);
145 fwrite(it->second.second, it->second.second[1]+2, 1, f);
151 eEPGCache* eEPGCache::instance;
152 pthread_mutex_t eEPGCache::cache_lock=
153 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
154 pthread_mutex_t eEPGCache::channel_map_lock=
155 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
157 DEFINE_REF(eEPGCache)
159 eEPGCache::eEPGCache()
160 :messages(this,1), cleanTimer(this)//, paused(0)
162 eDebug("[EPGC] Initialized EPGCache");
164 CONNECT(messages.recv_msg, eEPGCache::gotMessage);
165 CONNECT(eDVBLocalTimeHandler::getInstance()->m_timeUpdated, eEPGCache::timeUpdated);
166 CONNECT(cleanTimer.timeout, eEPGCache::cleanLoop);
168 ePtr<eDVBResourceManager> res_mgr;
169 eDVBResourceManager::getInstance(res_mgr);
171 eDebug("[eEPGCache] no resource manager !!!!!!!");
173 res_mgr->connectChannelAdded(slot(*this,&eEPGCache::DVBChannelAdded), m_chanAddedConn);
177 void eEPGCache::timeUpdated()
179 if ( !thread_running() )
181 eDebug("[EPGC] time updated.. start EPG Mainloop");
185 messages.send(Message(Message::timeChanged));
188 void eEPGCache::DVBChannelAdded(eDVBChannel *chan)
192 // eDebug("[eEPGCache] add channel %p", chan);
193 channel_data *data = new channel_data(this);
194 data->channel = chan;
195 data->prevChannelState = -1;
196 singleLock s(channel_map_lock);
197 m_knownChannels.insert( std::pair<iDVBChannel*, channel_data* >(chan, data) );
198 chan->connectStateChange(slot(*this, &eEPGCache::DVBChannelStateChanged), data->m_stateChangedConn);
202 void eEPGCache::DVBChannelRunning(iDVBChannel *chan)
204 singleLock s(channel_map_lock);
205 channelMapIterator it =
206 m_knownChannels.find(chan);
207 if ( it == m_knownChannels.end() )
208 eDebug("[eEPGCache] will start non existing channel %p !!!", chan);
211 channel_data &data = *it->second;
212 ePtr<eDVBResourceManager> res_mgr;
213 if ( eDVBResourceManager::getInstance( res_mgr ) )
214 eDebug("[eEPGCache] no res manager!!");
217 ePtr<iDVBDemux> demux;
218 if ( data.channel->getDemux(demux, 0) )
220 eDebug("[eEPGCache] no demux!!");
225 RESULT res = demux->createSectionReader( this, data.m_NowNextReader );
228 eDebug("[eEPGCache] couldnt initialize nownext reader!!");
232 res = demux->createSectionReader( this, data.m_ScheduleReader );
235 eDebug("[eEPGCache] couldnt initialize schedule reader!!");
239 res = demux->createSectionReader( this, data.m_ScheduleOtherReader );
242 eDebug("[eEPGCache] couldnt initialize schedule other reader!!");
246 messages.send(Message(Message::startChannel, chan));
247 // -> gotMessage -> changedService
253 void eEPGCache::DVBChannelStateChanged(iDVBChannel *chan)
255 channelMapIterator it =
256 m_knownChannels.find(chan);
257 if ( it != m_knownChannels.end() )
260 chan->getState(state);
261 if ( it->second->prevChannelState != state )
265 case iDVBChannel::state_ok:
267 eDebug("[eEPGCache] channel %p running", chan);
268 DVBChannelRunning(chan);
271 case iDVBChannel::state_release:
273 eDebug("[eEPGCache] remove channel %p", chan);
274 messages.send(Message(Message::leaveChannel, chan));
275 while(!it->second->can_delete)
278 m_knownChannels.erase(it);
279 // -> gotMessage -> abortEPG
282 default: // ignore all other events
285 it->second->prevChannelState = state;
290 void eEPGCache::sectionRead(const __u8 *data, int source, channel_data *channel)
292 eit_t *eit = (eit_t*) data;
294 int len=HILO(eit->section_length)-1;//+3-4;
299 // This fixed the EPG on the Multichoice irdeto systems
300 // the EIT packet is non-compliant.. their EIT packet stinks
301 if ( data[ptr-1] < 0x40 )
304 uniqueEPGKey service( HILO(eit->service_id), HILO(eit->original_network_id), HILO(eit->transport_stream_id) );
305 eit_event_struct* eit_event = (eit_event_struct*) (data+ptr);
309 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);
310 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
312 if ( TM != 3599 && TM > -1)
313 channel->haveData |= source;
315 singleLock s(cache_lock);
316 // hier wird immer eine eventMap zurück gegeben.. entweder eine vorhandene..
317 // oder eine durch [] erzeugte
318 std::pair<eventMap,timeMap> &servicemap = eventDB[service];
319 eventMap::iterator prevEventIt = servicemap.first.end();
320 timeMap::iterator prevTimeIt = servicemap.second.end();
324 eit_event_size = HILO(eit_event->descriptors_loop_length)+EIT_LOOP_SIZE;
326 duration = fromBCD(eit_event->duration_1)*3600+fromBCD(eit_event->duration_2)*60+fromBCD(eit_event->duration_3);
328 eit_event->start_time_1,
329 eit_event->start_time_2,
330 eit_event->start_time_3,
331 eit_event->start_time_4,
332 eit_event->start_time_5);
337 if ( TM != 3599 && (TM+duration < now || TM > now+14*24*60*60) )
340 if ( now <= (TM+duration) || TM == 3599 /*NVOD Service*/ ) // old events should not be cached
342 __u16 event_id = HILO(eit_event->event_id);
343 // eDebug("event_id is %d sid is %04x", event_id, service.sid);
346 int ev_erase_count = 0;
347 int tm_erase_count = 0;
349 // search in eventmap
350 eventMap::iterator ev_it =
351 servicemap.first.find(event_id);
353 // entry with this event_id is already exist ?
354 if ( ev_it != servicemap.first.end() )
356 if ( source > ev_it->second->type ) // update needed ?
357 goto next; // when not.. the skip this entry
359 // search this event in timemap
360 timeMap::iterator tm_it_tmp =
361 servicemap.second.find(ev_it->second->getStartTime());
363 if ( tm_it_tmp != servicemap.second.end() )
365 if ( tm_it_tmp->first == TM ) // correct eventData
368 delete ev_it->second;
369 evt = new eventData(eit_event, eit_event_size, source);
371 tm_it_tmp->second=evt;
377 // delete the found record from timemap
378 servicemap.second.erase(tm_it_tmp);
379 prevTimeIt=servicemap.second.end();
384 // search in timemap, for check of a case if new time has coincided with time of other event
385 // or event was is not found in eventmap
386 timeMap::iterator tm_it =
387 servicemap.second.find(TM);
389 if ( tm_it != servicemap.second.end() )
391 // i think, if event is not found on eventmap, but found on timemap updating nevertheless demands
393 if ( source > tm_it->second->type && tm_erase_count == 0 ) // update needed ?
394 goto next; // when not.. the skip this entry
397 // search this time in eventmap
398 eventMap::iterator ev_it_tmp =
399 servicemap.first.find(tm_it->second->getEventID());
401 if ( ev_it_tmp != servicemap.first.end() )
404 // delete the found record from eventmap
405 servicemap.first.erase(ev_it_tmp);
406 prevEventIt=servicemap.first.end();
410 evt = new eventData(eit_event, eit_event_size, source);
412 bool consistencyCheck=true;
414 if (ev_erase_count > 0 && tm_erase_count > 0) // 2 different pairs have been removed
417 delete ev_it->second;
418 delete tm_it->second;
422 else if (ev_erase_count == 0 && tm_erase_count > 0)
425 delete ev_it->second;
426 tm_it=prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
429 else if (ev_erase_count > 0 && tm_erase_count == 0)
432 delete tm_it->second;
433 ev_it=prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
436 else // added new eventData
439 consistencyCheck=false;
441 prevEventIt=servicemap.first.insert( prevEventIt, std::pair<const __u16, eventData*>( event_id, evt) );
442 prevTimeIt=servicemap.second.insert( prevTimeIt, std::pair<const time_t, eventData*>( TM, evt ) );
445 if ( consistencyCheck )
447 if ( tm_it->second != evt || ev_it->second != evt )
448 eFatal("tm_it->second != ev_it->second");
449 else if ( tm_it->second->getStartTime() != tm_it->first )
450 eFatal("event start_time(%d) non equal timemap key(%d)",
451 tm_it->second->getStartTime(), tm_it->first );
452 else if ( tm_it->first != TM )
453 eFatal("timemap key(%d) non equal TM(%d)",
455 else if ( ev_it->second->getEventID() != ev_it->first )
456 eFatal("event_id (%d) non equal event_map key(%d)",
457 ev_it->second->getEventID(), ev_it->first);
458 else if ( ev_it->first != event_id )
459 eFatal("eventmap key(%d) non equal event_id(%d)",
460 ev_it->first, event_id );
466 if ( servicemap.first.size() != servicemap.second.size() )
468 FILE *f = fopen("/hdd/event_map.txt", "w+");
470 for (eventMap::iterator it(servicemap.first.begin())
471 ; it != servicemap.first.end(); ++it )
472 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
473 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
475 f = fopen("/hdd/time_map.txt", "w+");
477 for (timeMap::iterator it(servicemap.second.begin())
478 ; it != servicemap.second.end(); ++it )
479 fprintf(f, "%d(key %d) -> time %d, event_id %d, data %p\n",
480 i++, (int)it->first, (int)it->second->getStartTime(), (int)it->second->getEventID(), it->second );
483 eFatal("(1)map sizes not equal :( sid %04x tsid %04x onid %04x size %d size2 %d",
484 service.sid, service.tsid, service.onid,
485 servicemap.first.size(), servicemap.second.size() );
488 ptr += eit_event_size;
489 eit_event=(eit_event_struct*)(((__u8*)eit_event)+eit_event_size);
493 void eEPGCache::flushEPG(const uniqueEPGKey & s)
495 eDebug("[EPGC] flushEPG %d", (int)(bool)s);
496 singleLock l(cache_lock);
497 if (s) // clear only this service
499 eventCache::iterator it = eventDB.find(s);
500 if ( it != eventDB.end() )
502 eventMap &evMap = it->second.first;
503 timeMap &tmMap = it->second.second;
505 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
510 // TODO .. search corresponding channel for removed service and remove this channel from lastupdated map
513 else // clear complete EPG Cache
515 for (eventCache::iterator it(eventDB.begin());
516 it != eventDB.end(); ++it)
518 eventMap &evMap = it->second.first;
519 timeMap &tmMap = it->second.second;
520 for (eventMap::iterator i = evMap.begin(); i != evMap.end(); ++i)
526 channelLastUpdated.clear();
527 singleLock m(channel_map_lock);
528 for (channelMapIterator it(m_knownChannels.begin()); it != m_knownChannels.end(); ++it)
529 it->second->startEPG();
531 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
534 void eEPGCache::cleanLoop()
536 singleLock s(cache_lock);
537 if (!eventDB.empty())
539 eDebug("[EPGC] start cleanloop");
541 time_t now = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
543 for (eventCache::iterator DBIt = eventDB.begin(); DBIt != eventDB.end(); DBIt++)
545 for (timeMap::iterator It = DBIt->second.second.begin(); It != DBIt->second.second.end() && It->first < now;)
547 if ( now > (It->first+It->second->getDuration()) ) // outdated normal entry (nvod references to)
549 // remove entry from eventMap
550 eventMap::iterator b(DBIt->second.first.find(It->second->getEventID()));
551 if ( b != DBIt->second.first.end() )
553 // release Heap Memory for this entry (new ....)
554 // eDebug("[EPGC] delete old event (evmap)");
555 DBIt->second.first.erase(b);
558 // remove entry from timeMap
559 // eDebug("[EPGC] release heap mem");
561 DBIt->second.second.erase(It++);
562 // eDebug("[EPGC] delete old event (timeMap)");
568 eDebug("[EPGC] stop cleanloop");
569 eDebug("[EPGC] %i bytes for cache used", eventData::CacheSize);
571 cleanTimer.start(CLEAN_INTERVAL,true);
574 eEPGCache::~eEPGCache()
576 messages.send(Message::quit);
577 kill(); // waiting for thread shutdown
578 singleLock s(cache_lock);
579 for (eventCache::iterator evIt = eventDB.begin(); evIt != eventDB.end(); evIt++)
580 for (eventMap::iterator It = evIt->second.first.begin(); It != evIt->second.first.end(); It++)
584 void eEPGCache::gotMessage( const Message &msg )
589 flushEPG(msg.service);
591 case Message::startChannel:
593 singleLock s(channel_map_lock);
594 channelMapIterator channel =
595 m_knownChannels.find(msg.channel);
596 if ( channel != m_knownChannels.end() )
597 channel->second->startChannel();
600 case Message::leaveChannel:
602 singleLock s(channel_map_lock);
603 channelMapIterator channel =
604 m_knownChannels.find(msg.channel);
605 if ( channel != m_knownChannels.end() )
606 channel->second->abortEPG();
612 case Message::timeChanged:
616 eDebug("unhandled EPGCache Message!!");
621 void eEPGCache::thread()
630 void eEPGCache::load()
632 FILE *f = fopen("/hdd/epg.dat", "r");
635 unsigned char md5_saved[16];
636 unsigned char md5[16];
641 if (!md5_file("/hdd/epg.dat", 1, md5))
643 FILE *f = fopen("/hdd/epg.dat.md5", "r");
646 fread( md5_saved, 16, 1, f);
648 if ( !memcmp(md5_saved, md5, 16) )
656 fread( text1, 13, 1, f);
657 if ( !strncmp( text1, "ENIGMA_EPG_V4", 13) )
659 fread( &size, sizeof(int), 1, f);
666 fread( &key, sizeof(uniqueEPGKey), 1, f);
667 fread( &size, sizeof(int), 1, f);
673 fread( &type, sizeof(__u8), 1, f);
674 fread( &len, sizeof(__u8), 1, f);
675 event = new eventData(0, len, type);
676 event->EITdata = new __u8[len];
677 eventData::CacheSize+=len;
678 fread( event->EITdata, len, 1, f);
679 evMap[ event->getEventID() ]=event;
680 tmMap[ event->getStartTime() ]=event;
683 eventDB[key]=std::pair<eventMap,timeMap>(evMap,tmMap);
686 eDebug("%d events read from /hdd/epg.dat", cnt);
689 eDebug("[EPGC] don't read old epg database");
695 void eEPGCache::save()
699 if (statfs("/hdd", &s)<0)
707 // prevent writes to builtin flash
708 if ( tmp < 1024*1024*50 ) // storage size < 50MB
711 // check for enough free space on storage
714 if ( tmp < (eventData::CacheSize*12)/10 ) // 20% overhead
717 FILE *f = fopen("/hdd/epg.dat", "w");
721 const char *text = "ENIGMA_EPG_V4";
722 fwrite( text, 13, 1, f );
723 int size = eventDB.size();
724 fwrite( &size, sizeof(int), 1, f );
725 for (eventCache::iterator service_it(eventDB.begin()); service_it != eventDB.end(); ++service_it)
727 timeMap &timemap = service_it->second.second;
728 fwrite( &service_it->first, sizeof(uniqueEPGKey), 1, f);
729 size = timemap.size();
730 fwrite( &size, sizeof(int), 1, f);
731 for (timeMap::iterator time_it(timemap.begin()); time_it != timemap.end(); ++time_it)
733 __u8 len = time_it->second->ByteSize;
734 fwrite( &time_it->second->type, sizeof(__u8), 1, f );
735 fwrite( &len, sizeof(__u8), 1, f);
736 fwrite( time_it->second->EITdata, len, 1, f);
740 eDebug("%d events written to /hdd/epg.dat", cnt);
744 unsigned char md5[16];
745 if (!md5_file("/hdd/epg.dat", 1, md5))
747 FILE *f = fopen("/hdd/epg.dat.md5", "w");
750 fwrite( md5, 16, 1, f);
758 eEPGCache::channel_data::channel_data(eEPGCache *ml)
760 ,abortTimer(ml), zapTimer(ml)
761 ,state(0), isRunning(0), haveData(0), can_delete(1)
763 CONNECT(zapTimer.timeout, eEPGCache::channel_data::startEPG);
764 CONNECT(abortTimer.timeout, eEPGCache::channel_data::abortNonAvail);
767 bool eEPGCache::channel_data::finishEPG()
769 if (!isRunning) // epg ready
771 eDebug("[EPGC] stop caching events(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
772 zapTimer.start(UPDATE_INTERVAL, 1);
773 eDebug("[EPGC] next update in %i min", UPDATE_INTERVAL / 60000);
774 for (int i=0; i < 3; ++i)
776 seenSections[i].clear();
777 calcedSections[i].clear();
779 singleLock l(cache->cache_lock);
780 cache->channelLastUpdated[channel->getChannelID()] = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
787 void eEPGCache::channel_data::startEPG()
789 eDebug("[EPGC] start caching events(%d)", eDVBLocalTimeHandler::getInstance()->difference()+time(0));
793 for (int i=0; i < 3; ++i)
795 seenSections[i].clear();
796 calcedSections[i].clear();
799 eDVBSectionFilterMask mask;
800 memset(&mask, 0, sizeof(mask));
802 mask.flags = eDVBSectionFilterMask::rfCRC;
806 m_NowNextReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_NowNextConn);
807 m_NowNextReader->start(mask);
808 isRunning |= NOWNEXT;
812 m_ScheduleReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleConn);
813 m_ScheduleReader->start(mask);
814 isRunning |= SCHEDULE;
818 m_ScheduleOtherReader->connectRead(slot(*this, &eEPGCache::channel_data::readData), m_ScheduleOtherConn);
819 m_ScheduleOtherReader->start(mask);
820 isRunning |= SCHEDULE_OTHER;
822 abortTimer.start(7000,true);
825 void eEPGCache::channel_data::abortNonAvail()
829 if ( !(haveData&eEPGCache::NOWNEXT) && (isRunning&eEPGCache::NOWNEXT) )
831 eDebug("[EPGC] abort non avail nownext reading");
832 isRunning &= ~eEPGCache::NOWNEXT;
833 m_NowNextReader->stop();
836 if ( !(haveData&eEPGCache::SCHEDULE) && (isRunning&eEPGCache::SCHEDULE) )
838 eDebug("[EPGC] abort non avail schedule reading");
839 isRunning &= ~SCHEDULE;
840 m_ScheduleReader->stop();
843 if ( !(haveData&eEPGCache::SCHEDULE_OTHER) && (isRunning&eEPGCache::SCHEDULE_OTHER) )
845 eDebug("[EPGC] abort non avail schedule_other reading");
846 isRunning &= ~SCHEDULE_OTHER;
847 m_ScheduleOtherReader->stop();
848 m_ScheduleOtherConn=0;
851 abortTimer.start(90000, true);
855 for (int i=0; i < 3; ++i)
857 seenSections[i].clear();
858 calcedSections[i].clear();
866 void eEPGCache::channel_data::startChannel()
868 updateMap::iterator It = cache->channelLastUpdated.find( channel->getChannelID() );
870 int update = ( It != cache->channelLastUpdated.end() ? ( UPDATE_INTERVAL - ( (time(0)+eDVBLocalTimeHandler::getInstance()->difference()-It->second) * 1000 ) ) : ZAP_DELAY );
872 if (update < ZAP_DELAY)
875 zapTimer.start(update, 1);
877 eDebug("[EPGC] next update in %i min", update/60000);
878 else if (update >= 1000)
879 eDebug("[EPGC] next update in %i sec", update/1000);
882 void eEPGCache::channel_data::abortEPG()
884 for (int i=0; i < 3; ++i)
886 seenSections[i].clear();
887 calcedSections[i].clear();
893 eDebug("[EPGC] abort caching events !!");
894 if (isRunning & eEPGCache::SCHEDULE)
896 isRunning &= ~eEPGCache::SCHEDULE;
897 m_ScheduleReader->stop();
900 if (isRunning & eEPGCache::NOWNEXT)
902 isRunning &= ~eEPGCache::NOWNEXT;
903 m_NowNextReader->stop();
906 if (isRunning & SCHEDULE_OTHER)
908 isRunning &= ~eEPGCache::SCHEDULE_OTHER;
909 m_ScheduleOtherReader->stop();
910 m_ScheduleOtherConn=0;
916 void eEPGCache::channel_data::readData( const __u8 *data)
919 eDebug("get Null pointer from section reader !!");
924 iDVBSectionReader *reader=NULL;
928 reader=m_NowNextReader;
929 source=eEPGCache::NOWNEXT;
933 reader=m_ScheduleReader;
934 source=eEPGCache::SCHEDULE;
938 reader=m_ScheduleOtherReader;
939 source=eEPGCache::SCHEDULE_OTHER;
943 eDebug("[EPGC] unknown table_id !!!");
946 tidMap &seenSections = this->seenSections[map];
947 tidMap &calcedSections = this->calcedSections[map];
948 if ( state == 1 && calcedSections == seenSections || state > 1 )
950 eDebugNoNewLine("[EPGC] ");
953 case eEPGCache::NOWNEXT:
955 eDebugNoNewLine("nownext");
957 case eEPGCache::SCHEDULE:
959 eDebugNoNewLine("schedule");
961 case eEPGCache::SCHEDULE_OTHER:
962 m_ScheduleOtherConn=0;
963 eDebugNoNewLine("schedule other");
965 default: eDebugNoNewLine("unknown");break;
967 eDebug(" finished(%d)", time(0)+eDVBLocalTimeHandler::getInstance()->difference());
970 isRunning &= ~source;
976 eit_t *eit = (eit_t*) data;
977 __u32 sectionNo = data[0] << 24;
978 sectionNo |= data[3] << 16;
979 sectionNo |= data[4] << 8;
980 sectionNo |= eit->section_number;
982 tidMap::iterator it =
983 seenSections.find(sectionNo);
985 if ( it == seenSections.end() )
987 seenSections.insert(sectionNo);
988 calcedSections.insert(sectionNo);
989 __u32 tmpval = sectionNo & 0xFFFFFF00;
990 __u8 incr = source == NOWNEXT ? 1 : 8;
991 for ( int i = 0; i <= eit->last_section_number; i+=incr )
993 if ( i == eit->section_number )
995 for (int x=i; x <= eit->segment_last_section_number; ++x)
996 calcedSections.insert(tmpval|(x&0xFF));
999 calcedSections.insert(tmpval|(i&0xFF));
1001 cache->sectionRead(data, source, this);
1007 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eventData *&result )
1008 // if t == -1 we search the current event...
1010 singleLock s(cache_lock);
1011 uniqueEPGKey key(service);
1013 // check if EPG for this service is ready...
1014 eventCache::iterator It = eventDB.find( key );
1015 if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached ?
1018 t = time(0)+eDVBLocalTimeHandler::getInstance()->difference();
1019 timeMap::iterator i = It->second.second.lower_bound(t); // find > or equal
1020 if ( i != It->second.second.end() )
1022 if ( i->second->getStartTime() != t )
1024 timeMap::iterator x = i;
1026 if ( x != It->second.second.end() )
1028 time_t start_time = x->second->getStartTime();
1031 if (t > (start_time+x->second->getDuration()))
1045 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, const eit_event_struct *&result )
1047 singleLock s(cache_lock);
1048 const eventData *data=0;
1049 RESULT ret = lookupEventTime(service, t, data);
1051 result = data->get();
1055 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, Event *& result )
1057 singleLock s(cache_lock);
1058 const eventData *data=0;
1059 RESULT ret = lookupEventTime(service, t, data);
1061 result = new Event((uint8_t*)data->get());
1065 RESULT eEPGCache::lookupEventTime(const eServiceReference &service, time_t t, ePtr<eServiceEvent> &result )
1067 singleLock s(cache_lock);
1068 const eventData *data=0;
1069 RESULT ret = lookupEventTime(service, t, data);
1072 Event ev((uint8_t*)data->get());
1073 result = new eServiceEvent();
1074 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1075 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1080 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eventData *&result )
1082 singleLock s(cache_lock);
1083 uniqueEPGKey key( service );
1085 eventCache::iterator It = eventDB.find( key );
1086 if ( It != eventDB.end() && !It->second.first.empty() ) // entrys cached?
1088 eventMap::iterator i( It->second.first.find( event_id ));
1089 if ( i != It->second.first.end() )
1097 eDebug("event %04x not found in epgcache", event_id);
1103 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, const eit_event_struct *&result)
1105 singleLock s(cache_lock);
1106 const eventData *data=0;
1107 RESULT ret = lookupEventId(service, event_id, data);
1109 result = data->get();
1113 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, Event *& result)
1115 singleLock s(cache_lock);
1116 const eventData *data=0;
1117 RESULT ret = lookupEventId(service, event_id, data);
1119 result = new Event((uint8_t*)data->get());
1123 RESULT eEPGCache::lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &result)
1125 singleLock s(cache_lock);
1126 const eventData *data=0;
1127 RESULT ret = lookupEventId(service, event_id, data);
1130 Event ev((uint8_t*)data->get());
1131 result = new eServiceEvent();
1132 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1133 ret = result->parseFrom(&ev, (ref.getTransportStreamID().get()<<16)|ref.getOriginalNetworkID().get());
1138 RESULT eEPGCache::startTimeQuery(const eServiceReference &service, time_t begin, int minutes)
1140 eventCache::iterator It = eventDB.find( service );
1141 if ( It != eventDB.end() && It->second.second.size() )
1143 m_timemap_end = minutes != -1 ? It->second.second.upper_bound(begin+minutes*60) : It->second.second.end();
1146 m_timemap_cursor = It->second.second.lower_bound(begin);
1147 if ( m_timemap_cursor != It->second.second.end() )
1149 if ( m_timemap_cursor->second->getStartTime() != begin )
1151 timeMap::iterator x = m_timemap_cursor;
1153 if ( x != It->second.second.end() )
1155 time_t start_time = x->second->getStartTime();
1156 if ( begin > start_time && begin < (start_time+x->second->getDuration()))
1157 m_timemap_cursor = x;
1163 m_timemap_cursor = It->second.second.begin();
1164 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)service;
1165 currentQueryTsidOnid = (ref.getTransportStreamID().get()<<16) | ref.getOriginalNetworkID().get();
1171 RESULT eEPGCache::getNextTimeEntry(const eventData *& result)
1173 if ( m_timemap_cursor != m_timemap_end )
1175 result = m_timemap_cursor++->second;
1181 RESULT eEPGCache::getNextTimeEntry(const eit_event_struct *&result)
1183 if ( m_timemap_cursor != m_timemap_end )
1185 result = m_timemap_cursor++->second->get();
1191 RESULT eEPGCache::getNextTimeEntry(Event *&result)
1193 if ( m_timemap_cursor != m_timemap_end )
1195 result = new Event((uint8_t*)m_timemap_cursor++->second->get());
1201 RESULT eEPGCache::getNextTimeEntry(ePtr<eServiceEvent> &result)
1203 if ( m_timemap_cursor != m_timemap_end )
1205 Event ev((uint8_t*)m_timemap_cursor++->second->get());
1206 result = new eServiceEvent();
1207 return result->parseFrom(&ev, currentQueryTsidOnid);
1212 void fillTuple(PyObject *tuple, char *argstring, int argcount, PyObject *service, ePtr<eServiceEvent> &ptr, PyObject *nowTime, PyObject *service_name )
1216 while(pos < argcount)
1218 bool inc_refcount=false;
1219 switch(argstring[pos])
1221 case 'I': // Event Id
1222 tmp = ptr ? PyLong_FromLong(ptr->getEventId()) : NULL;
1224 case 'B': // Event Begin Time
1225 tmp = ptr ? PyLong_FromLong(ptr->getBeginTime()) : NULL;
1227 case 'D': // Event Duration
1228 tmp = ptr ? PyLong_FromLong(ptr->getDuration()) : NULL;
1230 case 'T': // Event Title
1231 tmp = ptr ? PyString_FromString(ptr->getEventName().c_str()) : NULL;
1233 case 'S': // Event Short Description
1234 tmp = ptr ? PyString_FromString(ptr->getShortDescription().c_str()) : NULL;
1236 case 'E': // Event Extended Description
1237 tmp = ptr ? PyString_FromString(ptr->getExtendedDescription().c_str()) : NULL;
1239 case 'C': // Current Time
1241 inc_refcount = true;
1243 case 'R': // service reference string
1245 inc_refcount = true;
1247 case 'N': // service name
1249 inc_refcount = true;
1254 inc_refcount = true;
1258 PyTuple_SET_ITEM(tuple, pos++, tmp);
1262 PyObject *handleEvent(ePtr<eServiceEvent> &ptr, PyObject *dest_list, char* argstring, int argcount, PyObject *service, PyObject *nowTime, PyObject *service_name, PyObject *convertFunc, PyObject *convertFuncArgs)
1266 fillTuple(convertFuncArgs, argstring, argcount, service, ptr, nowTime, service_name);
1267 PyObject *result = PyEval_CallObject(convertFunc, convertFuncArgs);
1272 Py_DECREF(convertFuncArgs);
1275 PyList_Append(dest_list, result);
1279 PyObject *tuple = PyTuple_New(argcount);
1280 fillTuple(tuple, argstring, argcount, service, ptr, nowTime, service_name);
1281 PyList_Append(dest_list, tuple);
1286 // here we get a list with tuples
1287 // first tuple entry is the servicereference
1288 // the second is the type of query (0 = time, 1 = event_id)
1290 // when type is eventid it is the event_id
1291 // when type is time then it is the start_time ( 0 for now_time )
1292 // the fourth is the end_time .. ( optional )
1294 /* argv is a python string
1296 B = Event Begin Time
1299 S = Event Short Description
1300 E = Event Extended Description
1302 R = Service Reference
1306 PyObject *eEPGCache::lookupEvent(PyObject *list, PyObject *convertFunc)
1308 PyObject *convertFuncArgs=NULL;
1310 char *argstring=NULL;
1311 if (!PyList_Check(list))
1313 PyErr_SetString(PyExc_StandardError,
1319 int listSize=PyList_Size(list);
1322 PyErr_SetString(PyExc_StandardError,
1323 "not params given");
1324 eDebug("not params given");
1329 PyObject *argv=PyList_GET_ITEM(list, 0); // borrowed reference!
1330 if (PyString_Check(argv))
1332 argstring = PyString_AS_STRING(argv);
1336 argstring = "I"; // just event id as default
1337 argcount = strlen(argstring);
1338 // eDebug("have %d args('%s')", argcount, argstring);
1342 if (!PyCallable_Check(convertFunc))
1344 PyErr_SetString(PyExc_StandardError,
1345 "convertFunc must be callable");
1346 eDebug("convertFunc is not callable");
1349 convertFuncArgs = PyTuple_New(argcount);
1352 PyObject *nowTime = strchr(argstring, 'C') ?
1353 PyLong_FromLong(time(0)+eDVBLocalTimeHandler::getInstance()->difference()) :
1356 bool must_get_service_name = strchr(argstring, 'N') ? true : false;
1359 PyObject *dest_list=PyList_New(0);
1360 while(listSize > listIt)
1362 PyObject *item=PyList_GET_ITEM(list, listIt++); // borrowed reference!
1363 if (PyTuple_Check(item))
1369 int tupleSize=PyTuple_Size(item);
1371 PyObject *service=NULL;
1372 while(tupleSize > tupleIt) // parse query args
1374 PyObject *entry=PyTuple_GET_ITEM(item, tupleIt); // borrowed reference!
1379 if (!PyString_Check(entry))
1381 eDebug("tuple entry 0 is no a string");
1388 type=PyInt_AsLong(entry);
1389 if (type < 0 || type > 1)
1391 eDebug("unknown type %d", type);
1396 event_id=stime=PyInt_AsLong(entry);
1399 minutes=PyInt_AsLong(entry);
1402 eDebug("unneeded extra argument");
1406 eServiceReference ref(PyString_AS_STRING(service));
1407 if (ref.type != eServiceReference::idDVB)
1409 eDebug("service reference for epg query is not valid");
1412 PyObject *service_name=NULL;
1413 if (must_get_service_name)
1415 ePtr<iStaticServiceInformation> sptr;
1416 eServiceCenterPtr service_center;
1417 eServiceCenter::getPrivInstance(service_center);
1420 service_center->info(ref, sptr);
1424 sptr->getName(ref, name);
1426 service_name = PyString_FromString(name.c_str());
1430 service_name = PyString_FromString("<n/a>");
1435 if (!startTimeQuery(ref, stime, minutes))
1437 ePtr<eServiceEvent> ptr;
1438 while (!getNextTimeEntry(ptr))
1440 PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs);
1449 ePtr<eServiceEvent> ptr;
1453 lookupEventTime(ref, stime, ptr);
1455 lookupEventId(ref, event_id, ptr);
1457 PyObject *ret = handleEvent(ptr, dest_list, argstring, argcount, service, nowTime, service_name, convertFunc, convertFuncArgs);
1462 Py_DECREF(service_name);
1465 if (convertFuncArgs)
1466 Py_DECREF(convertFuncArgs);