add epgcache
[enigma2.git] / lib / dvb / epgcache.h
1 #ifndef __epgcache_h_
2 #define __epgcache_h_
3
4 #ifndef SWIG
5
6 #include <vector>
7 #include <list>
8 #include <ext/hash_map>
9
10 // check if gcc version >= 3.4
11 #if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ == 4 )
12 #else
13 #include <ext/stl_hash_fun.h>
14 #endif
15 #include <errno.h>
16
17 #include <lib/dvb/eit.h>
18 #include <lib/dvb/lowlevel/eit.h>
19 #include <lib/dvb/idvb.h>
20 #include <lib/dvb/demux.h>
21 #include <lib/dvb/dvbtime.h>
22 #include <lib/base/ebase.h>
23 #include <lib/base/thread.h>
24 #include <lib/base/message.h>
25
26 #define CLEAN_INTERVAL 60000    //  1 min
27 #define UPDATE_INTERVAL 3600000  // 60 min
28 #define ZAP_DELAY 2000          // 2 sek
29
30 #define HILO(x) (x##_hi << 8 | x##_lo)
31
32 class eventData;
33 class eServiceReferenceDVB;
34
35 struct uniqueEPGKey
36 {
37         int sid, onid, tsid;
38         uniqueEPGKey( const eServiceReferenceDVB &ref )
39                 :sid( ref.type != eServiceReference::idInvalid ? ref.getServiceID().get() : -1 )
40                 ,onid( ref.type != eServiceReference::idInvalid ? ref.getOriginalNetworkID().get() : -1 )
41                 ,tsid( ref.type != eServiceReference::idInvalid ? ref.getTransportStreamID().get() : -1 )
42         {
43         }
44         uniqueEPGKey()
45                 :sid(-1), onid(-1), tsid(-1)
46         {
47         }
48         uniqueEPGKey( int sid, int onid, int tsid )
49                 :sid(sid), onid(onid), tsid(tsid)
50         {
51         }
52         bool operator <(const uniqueEPGKey &a) const
53         {
54                 return memcmp( &sid, &a.sid, sizeof(int)*3)<0;
55         }
56         operator bool() const
57         { 
58                 return !(sid == -1 && onid == -1 && tsid == -1); 
59         }
60         bool operator==(const uniqueEPGKey &a) const
61         {
62                 return !memcmp( &sid, &a.sid, sizeof(int)*3);
63         }
64         struct equal
65         {
66                 bool operator()(const uniqueEPGKey &a, const uniqueEPGKey &b) const
67                 {
68                         return !memcmp( &a.sid, &b.sid, sizeof(int)*3);
69                 }
70         };
71 };
72
73 //eventMap is sorted by event_id
74 #define eventMap std::map<__u16, eventData*>
75 //timeMap is sorted by beginTime
76 #define timeMap std::map<time_t, eventData*>
77
78 #define tmpMap std::map<uniqueEPGKey, std::pair<time_t, int> >
79
80 #if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || __GNUC__ == 4 )  // check if gcc version >= 3.1
81         #define eventCache __gnu_cxx::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, __gnu_cxx::hash<uniqueEPGKey>, uniqueEPGKey::equal>
82         #define updateMap __gnu_cxx::hash_map<uniqueEPGKey, time_t, __gnu_cxx::hash<uniqueEPGKey>, uniqueEPGKey::equal >
83         namespace __gnu_cxx
84 #else // for older gcc use following
85         #define eventCache std::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, std::hash<uniqueEPGKey>, uniqueEPGKey::equal >
86         #define updateMap std::hash_map<uniqueEPGKey, time_t, std::hash<uniqueEPGKey>, uniqueEPGKey::equal >
87         namespace std
88 #endif
89 {
90 template<> struct hash<uniqueEPGKey>
91 {
92         inline size_t operator()( const uniqueEPGKey &x) const
93         {
94                 int v=(x.onid^x.sid);
95                 v^=v>>8;
96                 return v&0xFF;
97         }
98 };
99 }
100
101 class eventData
102 {
103         friend class eEPGCache;
104 private:
105         __u8* EITdata;
106         int ByteSize;
107 public:
108         int type;
109         static int CacheSize;
110         eventData(const eit_event_struct* e, int size, int type)
111         :ByteSize(size), type(type)
112         {
113                 CacheSize+=size;
114                 EITdata = new __u8[size];
115                 if (e)
116                         memcpy(EITdata, (__u8*) e, size);
117         }
118         ~eventData()
119         {
120                 CacheSize-=ByteSize;
121                 delete [] EITdata;
122         }
123         operator const eit_event_struct*() const
124         {
125                 return (const eit_event_struct*) EITdata;
126         }
127         const eit_event_struct* get() const
128         {
129                 return (const eit_event_struct*) EITdata;
130         }
131         int getEventID()
132         {
133                 return HILO( ((const eit_event_struct*) EITdata)->event_id );
134         }
135         time_t getStartTime()
136         {
137                 return parseDVBtime(
138                         EITdata[2], EITdata[3],
139                         EITdata[4], EITdata[5], EITdata[6]);
140         }
141 };
142 #else
143         #include <lib/base/smartptr.h>
144 #endif
145
146 class eEPGCache: public eMainloop, private eThread, public Object
147 {
148         DECLARE_REF(eEPGCache)
149 public:
150 #ifndef SWIG
151         enum {NOWNEXT, SCHEDULE, SCHEDULE_OTHER};
152         struct Message
153         {
154                 enum
155                 {
156                         flush,
157                         startService,
158                         leaveChannel,
159                         pause,
160                         restart,
161                         updated,
162                         isavail,
163                         quit,
164                         timeChanged,
165                         leaveChannelFinished
166                 };
167                 int type;
168                 uniqueEPGKey service;
169                 union {
170                         int err;
171                         time_t time;
172                         bool avail;
173                 };
174                 Message()
175                         :type(0), time(0) {}
176                 Message(int type)
177                         :type(type) {}
178                 Message(int type, bool b)
179                         :type(type), avail(b) {}
180                 Message(int type, const eServiceReferenceDVB& service, int err=0)
181                         :type(type), service(service), err(err) {}
182                 Message(int type, time_t time)
183                         :type(type), time(time) {}
184         };
185         eFixedMessagePump<Message> messages;
186         eFixedMessagePump<Message> back_messages;
187 private:
188         static pthread_mutex_t cache_lock;
189         eServiceReferenceDVB next_service;
190         uniqueEPGKey current_service;
191         int paused;
192
193         int state;
194         __u8 isRunning, haveData;
195
196         ePtr<iDVBChannel> m_currentChannel;
197         ePtr<eConnection> m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn;
198         ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader;
199
200         int sectionRead(const __u8 *data, int source);
201         void readNowNextData(const __u8 *data);
202         void readScheduleData(const __u8 *data);
203         void readScheduleOtherData(const __u8 *data);
204
205         static eEPGCache *instance;
206
207         eventCache eventDB;
208         updateMap serviceLastUpdated;
209         tmpMap temp;
210         eTimer CleanTimer;
211         eTimer zapTimer;
212         eTimer abortTimer;
213         bool finishEPG();
214         void abortNonAvail();
215         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
216         void startEPG();
217
218         void changedService(const uniqueEPGKey &);
219         void abortEPG();
220
221         void cleanLoop();
222         void pauseEPG();
223         void restartEPG();
224         void thread();
225         void gotMessage(const Message &message);
226         void gotBackMessage(const Message &message);
227         void timeUpdated();
228         void save();
229         void load();
230         void leaveChannel(iDVBChannel *);
231 #endif
232 public:
233         static RESULT getInstance(ePtr<eEPGCache> &ptr);
234         // called from other thread context !!
235         void startCache(const eServiceReferenceDVB &);
236         Event *lookupEvent(const eServiceReferenceDVB &service, int event_id, bool plain=false );
237         Event *lookupEvent(const eServiceReferenceDVB &service, time_t=0, bool plain=false );
238 #ifndef SWIG
239         eEPGCache();
240         ~eEPGCache();
241
242         inline void Lock();
243         inline void Unlock();
244
245         const eventMap* getEventMap(const eServiceReferenceDVB &service);
246         const timeMap* getTimeMap(const eServiceReferenceDVB &service);
247         tmpMap* getUpdatedMap() { return &temp; }
248
249         Signal1<void, bool> EPGAvail;
250         Signal0<void> EPGUpdated;
251 #endif
252 };
253
254 TEMPLATE_TYPEDEF(ePtr<eEPGCache>,eEPGCachePtr);
255
256 inline const eventMap* eEPGCache::getEventMap(const eServiceReferenceDVB &service)
257 {
258         eventCache::iterator It = eventDB.find( service );
259         if ( It != eventDB.end() && It->second.first.size() )
260                 return &(It->second.first);
261         else
262                 return 0;
263 }
264
265 inline const timeMap* eEPGCache::getTimeMap(const eServiceReferenceDVB &service)
266 {
267         eventCache::iterator It = eventDB.find( service );
268         if ( It != eventDB.end() && It->second.second.size() )
269                 return &(It->second.second);
270         else
271                 return 0;
272 }
273
274 inline void eEPGCache::readNowNextData( const __u8 *data)
275 {
276         if ( !data || state == 2 )
277                 m_NowNextReader->stop();
278         else
279                 sectionRead(data, eEPGCache::NOWNEXT);
280 }
281
282 inline void eEPGCache::readScheduleData(const __u8 *data)
283 {
284         if ( !data || state == 2 )
285                 m_ScheduleReader->stop();
286         else
287                 sectionRead(data, eEPGCache::SCHEDULE);
288 }
289
290 inline void eEPGCache::readScheduleOtherData(const __u8 *data)
291 {
292         if ( !data || state == 2 )
293                 m_ScheduleOtherReader->stop();
294         else
295                 sectionRead(data, eEPGCache::SCHEDULE_OTHER);
296 }
297
298 inline void eEPGCache::Lock()
299 {
300         pthread_mutex_lock(&cache_lock);
301 }
302
303 inline void eEPGCache::Unlock()
304 {
305         pthread_mutex_unlock(&cache_lock);
306 }
307
308 #endif