switch to 4.2.x (initial add 4.2.0)
[enigma2.git] / usr / include / enigma2 / lib / dvb / epgcache.h
1 #ifndef __epgcache_h_
2 #define __epgcache_h_
3
4 //#define ENABLE_PRIVATE_EPG 1
5 //#define ENABLE_MHW_EPG 1
6
7 #ifndef SWIG
8
9 /* Test for gcc >= maj.min, as per __GNUC_PREREQ in glibc */
10 #if defined (__GNUC__) && defined (__GNUC_MINOR__)
11 #define __GNUC_PREREQ(maj, min) \
12           ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
13 #else
14 #define __GNUC_PREREQ(maj, min)  0
15 #endif
16
17 #include <vector>
18 #include <list>
19 #include <queue>
20 #if defined(__GXX_EXPERIMENTAL_CXX0X__)
21 #include <unordered_map>
22 #include <unordered_set>
23 #else
24 #include <ext/hash_map>
25 #include <ext/hash_set>
26 #endif
27
28 #include <errno.h>
29
30 #include <lib/dvb/eit.h>
31 #include <lib/dvb/idvb.h>
32 #include <lib/dvb/demux.h>
33 #include <lib/dvb/dvbtime.h>
34 #include <lib/base/ebase.h>
35 #include <lib/base/thread.h>
36 #include <lib/base/message.h>
37 #include <lib/service/event.h>
38 #include <lib/python/python.h>
39
40 #include <QSqlQuery>
41 #include <QSqlDatabase>
42
43 #define CLEAN_INTERVAL 60000    //  1 min
44 #define UPDATE_INTERVAL 3600000  // 60 min
45 #define ZAP_DELAY 2000          // 2 sek
46
47 #define HILO(x) (x##_hi << 8 | x##_lo)
48
49 class cacheData;
50 class eServiceReferenceDVB;
51 class eDVBServicePMTHandler;
52
53 struct uniqueEPGKey
54 {
55         int sid, onid, tsid, dvbnamespace;
56         uniqueEPGKey( const eServiceReference &ref )
57                 :sid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getServiceID().get() : -1 )
58                 ,onid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getOriginalNetworkID().get() : -1 )
59                 ,tsid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getTransportStreamID().get() : -1 )
60                 ,dvbnamespace( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getDVBNamespace().get() : -1 )
61         {
62         }
63         uniqueEPGKey()
64                 :sid(-1), onid(-1), tsid(-1), dvbnamespace(-1)
65         {
66         }
67         uniqueEPGKey( int sid, int onid, int tsid, int dvbnamespace )
68                 :sid(sid), onid(onid), tsid(tsid), dvbnamespace(dvbnamespace)
69         {
70         }
71         bool operator<(const uniqueEPGKey &a) const
72         {
73                 return dvbnamespace < a.dvbnamespace || (dvbnamespace == a.dvbnamespace
74                     && (onid < a.onid || (onid == a.onid
75                     && (tsid < a.tsid || (tsid == a.tsid
76                     && sid < a.sid)))));
77         }
78         bool operator==(const uniqueEPGKey &a) const
79         {
80                 return dvbnamespace == a.dvbnamespace
81                     && onid == a.onid
82                     && tsid == a.tsid
83                     && sid == a.sid;
84         }
85         operator bool() const
86         {
87                 return sid != -1
88                     || onid != -1
89                     || tsid != -1
90                     || dvbnamespace != -1;
91         }
92         struct equal
93         {
94                 bool operator()(const uniqueEPGKey &a, const uniqueEPGKey &b) const
95                 {
96                         return a == b;
97                 }
98         };
99 };
100
101 //eventMap is sorted by event_id
102 #define eventMap std::map<__u16, cacheData*>
103 //timeMap is sorted by beginTime
104 #define timeMap std::map<time_t, cacheData*>
105
106 #define channelMapIterator std::map<iDVBChannel*, channel_data*>::iterator
107 #define updateMap std::map<eDVBChannelID, time_t>
108
109 struct hash_uniqueEPGKey
110 {
111         inline size_t operator()( const uniqueEPGKey &x) const
112         {
113                 return (x.onid << 16) | x.tsid;
114         }
115 };
116
117 #define tidMap std::set<__u32>
118 #if defined(__GXX_EXPERIMENTAL_CXX0X__)
119         #define eventCache std::unordered_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal>
120         #ifdef ENABLE_PRIVATE_EPG
121                 #define contentTimeMap std::unordered_map<time_t, std::pair<time_t, __u16> >
122                 #define contentMap std::unordered_map<int, contentTimeMap >
123                 #define contentMaps std::unordered_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal >
124         #endif
125         #define pulledDBDataMap std::unordered_map<uniqueEPGKey, std::pair<std::set<uint32_t>, std::set<uint32_t> >, hash_uniqueEPGKey, uniqueEPGKey::equal>
126 #elif __GNUC_PREREQ(3,1)
127         #define eventCache __gnu_cxx::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal>
128         #ifdef ENABLE_PRIVATE_EPG
129                 #define contentTimeMap __gnu_cxx::hash_map<time_t, std::pair<time_t, __u16> >
130                 #define contentMap __gnu_cxx::hash_map<int, contentTimeMap >
131                 #define contentMaps __gnu_cxx::hash_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal >
132         #endif
133         #define pulledDBDataMap __gnu_cxx::hash_map<uniqueEPGKey, std::pair<std::set<int>, std::set<int> >, hash_uniqueEPGKey, uniqueEPGKey::equal>
134 #else // for older gcc use following
135         #define eventCache std::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal >
136         #ifdef ENABLE_PRIVATE_EPG
137                 #define contentTimeMap std::hash_map<time_t, std::pair<time_t, __u16> >
138                 #define contentMap std::hash_map<int, contentTimeMap >
139                 #define contentMaps std::hash_map<uniqueEPGKey, contentMap, hash_uniqueEPGKey, uniqueEPGKey::equal>
140         #endif
141         #define pulledDBDataMap std::hash_map<uniqueEPGKey, std::pair<std::set<int>, std::set<int> >, hash_uniqueEPGKey, uniqueEPGKey::equal>
142 #endif
143
144 #define descriptorPair std::pair<int,__u8*>
145 #define descriptorMap std::map<__u32, descriptorPair >
146
147 #endif
148
149 class eEPGCache;
150
151 class EPGDBThread: public eMainloop_native, private eThread, public Object
152 {
153         struct Message
154         {
155                 enum { unknown, process_data, shutdown, lock_service, unlock_service, unlock_first, cleanup_outdated };
156                 Message()
157                         :type(unknown)
158                 {
159                 }
160                 Message(const Message &msg)
161                         :type(msg.type), data(msg.data), service(msg.service), source(msg.source)
162                 {
163                 }
164                 Message(const struct uniqueEPGKey &service, int type)
165                         :type(type), service(service)
166                 {
167                 }
168                 Message(const struct uniqueEPGKey &service, const __u8 *data, int source)
169                         :type(process_data), data(data), service(service), source(source)
170                 {
171                 }
172                 Message(int type)
173                         :type(type)
174                 {
175                 }
176                 int type;
177                 const __u8 *data;
178                 struct uniqueEPGKey service;
179                 int source;
180         };
181         eEPGCache *m_epg_cache;
182         QSqlDatabase &m_db_rw;
183
184         pthread_mutex_t m_mutex;
185         pthread_cond_t m_cond;
186         std::queue<struct Message> m_queue;
187         int m_running;
188
189         std::map<uniqueEPGKey, int> m_locked_services;
190
191         void gotMessage(const Message &message);
192         void thread();
193 public:
194         EPGDBThread(eEPGCache *cache, QSqlDatabase &db);
195         /* this functions are called from main thread */
196         void sendData(const uniqueEPGKey &service, const __u8 *data, int source);
197         void lockService(const uniqueEPGKey &service);
198         void unlockService(const uniqueEPGKey &service, bool first=false);
199         void shutdown();
200         void start();
201         void cleanupOutdated();
202 };
203
204 class eEPGCache: public iObject, public eMainloop_native, private eThread, public Object
205 {
206 #ifndef SWIG
207         DECLARE_REF(eEPGCache)
208         struct channel_data: public sigc::trackable
209         {
210                 pthread_mutex_t channel_active;
211                 channel_data(eEPGCache*);
212                 eEPGCache *cache;
213                 ePtr<eTimer> abortTimer, zapTimer;
214                 int prevChannelState;
215                 int state;
216                 __u8 isRunning, haveData;
217                 ePtr<eDVBChannel> channel;
218                 ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn, m_ViasatConn;
219                 ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader, m_ViasatReader;
220                 tidMap seenSections[4], calcedSections[4];
221                 std::set<uniqueEPGKey> m_seen_services;
222 #ifdef ENABLE_PRIVATE_EPG
223                 ePtr<eTimer> startPrivateTimer;
224                 int m_PrevVersion;
225                 int m_PrivatePid;
226                 uniqueEPGKey m_PrivateService;
227                 ePtr<eConnection> m_PrivateConn;
228                 ePtr<iDVBSectionReader> m_PrivateReader;
229                 std::set<__u8> seenPrivateSections;
230                 void readPrivateData(const __u8 *data, int len);
231                 void startPrivateReader();
232 #endif
233 #ifdef ENABLE_MHW_EPG
234                 std::vector<mhw_channel_name_t> m_channels;
235                 std::map<__u8, mhw_theme_name_t> m_themes;
236                 std::map<__u32, mhw_title_t> m_titles;
237                 std::multimap<__u32, __u32> m_program_ids;
238                 ePtr<eConnection> m_MHWConn, m_MHWConn2;
239                 ePtr<iDVBSectionReader> m_MHWReader, m_MHWReader2;
240                 eDVBSectionFilterMask m_MHWFilterMask, m_MHWFilterMask2;
241                 ePtr<eTimer> m_MHWTimeoutTimer;
242                 __u16 m_mhw2_channel_pid, m_mhw2_title_pid, m_mhw2_summary_pid;
243                 bool m_MHWTimeoutet;
244                 void MHWTimeout() { m_MHWTimeoutet=true; }
245                 void readMHWData(const __u8 *data);
246                 void readMHWData2(const __u8 *data);
247                 void startMHWReader(__u16 pid, __u8 tid);
248                 void startMHWReader2(__u16 pid, __u8 tid, int ext=-1);
249                 void startTimeout(int msek);
250                 bool checkTimeout() { return m_MHWTimeoutet; }
251                 void cleanup();
252                 __u8 *delimitName( __u8 *in, __u8 *out, int len_in );
253                 void timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time);
254                 void timeMHW2DVB( int minutes, u_char *return_time);
255                 void timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time);
256                 void storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, const std::string &sumText, const __u8 *data);
257 #endif
258                 void readData(const __u8 *data, int len);
259                 void readDataViasat(const __u8 *data, int len);
260                 void startChannel();
261                 void startEPG();
262                 bool finishEPG();
263                 void abortEPG();
264                 void abortNonAvail();
265                 bool isCaching();
266         };
267         bool FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service);
268 public:
269         enum {PRIVATE=0, NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4
270 #ifdef ENABLE_MHW_EPG
271         ,MHW=8
272 #endif
273         ,VIASAT=16
274         };
275         struct Message
276         {
277                 enum
278                 {
279                         flush,
280                         startChannel,
281                         leaveChannel,
282                         load,
283                         save,
284                         quit,
285                         got_private_pid,
286                         got_mhw2_channel_pid,
287                         got_mhw2_title_pid,
288                         got_mhw2_summary_pid,
289                 };
290                 int type;
291                 iDVBChannel *channel;
292                 uniqueEPGKey service;
293                 union {
294                         int err;
295                         time_t time;
296                         bool avail;
297                         int pid;
298                 };
299                 Message()
300                         :type(0), time(0) {}
301                 Message(int type)
302                         :type(type) {}
303                 Message(int type, bool b)
304                         :type(type), avail(b) {}
305                 Message(int type, iDVBChannel *channel, int err=0)
306                         :type(type), channel(channel), err(err) {}
307                 Message(int type, const eServiceReference& service, int err=0)
308                         :type(type), service(service), err(err) {}
309                 Message(int type, time_t time)
310                         :type(type), time(time) {}
311         };
312         eFixedMessagePump<Message> messages;
313 private:
314         friend class channel_data;
315         friend class EPGDBThread;
316         static eEPGCache *instance;
317
318         ePtr<eTimer> cleanTimer;
319         ePtr<eTimer> stopTransaktionTimer;
320
321 //      ePtr<eTimer> flushToDBTimer;
322         std::map<iDVBChannel*, channel_data*> m_knownChannels;
323         ePtr<eConnection> m_chanAddedConn;
324
325         eventCache eventDB;
326         updateMap channelLastUpdated;
327         pulledDBDataMap pulledData;
328         static pthread_mutex_t cache_lock, channel_map_lock;
329
330 #ifdef ENABLE_PRIVATE_EPG
331         contentMaps content_time_tables;
332 #endif
333
334         int m_running;
335         int m_outdated_epg_timespan;
336         char m_filename[1024];
337
338         QSqlDatabase m_db_rw, m_db_ro;
339         QSqlQuery m_stmt_service_id_q;
340         QSqlQuery m_stmt_service_add;
341
342         QSqlQuery m_stmt_event_id_q;
343         QSqlQuery m_stmt_event_add;
344         QSqlQuery m_stmt_event_update;
345         QSqlQuery m_stmt_event_delete;
346         QSqlQuery m_stmt_event_cleanup_outdated;
347
348         QSqlQuery m_stmt_event_service_q;
349
350         QSqlQuery m_stmt_title_id_q;
351         QSqlQuery m_stmt_title_add;
352
353         QSqlQuery m_stmt_short_description_id_q;
354         QSqlQuery m_stmt_short_description_add;
355
356         QSqlQuery m_stmt_extended_description_id_q;
357         QSqlQuery m_stmt_extended_description_add;
358
359         QSqlQuery m_stmt_data_id_q;
360         QSqlQuery m_stmt_data_add;
361         QSqlQuery m_stmt_data_update;
362         QSqlQuery m_stmt_data_delete;
363
364         // queries for public access
365         QSqlQuery m_stmt_lookup_begin_time;
366         QSqlQuery m_stmt_lookup_event_id;
367         QSqlQuery m_stmt_lookup_now;
368         QSqlQuery m_stmt_lookup_before;
369
370         QSqlQuery m_stmt_lookup_all;
371         QSqlQuery m_stmt_lookup_end_time;
372
373         EPGDBThread m_db_thread;
374         __u8 *m_next_section_buffer;
375
376 // called from epgcache thread
377         void loadInternal();
378         void saveInternal();
379
380         void thread();  // thread function
381         bool copyDatabase(QSqlDatabase *memorydb, char* filename, bool save);
382 #ifdef ENABLE_PRIVATE_EPG
383         void privateSectionRead(const uniqueEPGKey &, const __u8 *);
384 #endif
385         void sectionRead(const __u8 *data, int source, channel_data *channel);
386         void gotMessage(const Message &message);
387         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
388
389 // called from db thread
390         void processData(const struct uniqueEPGKey &service, const __u8 *data, int source);
391         void pushToDB(const uniqueEPGKey &);
392         void pullFromDB(const uniqueEPGKey &);
393         void cleanupAfterPullPush();
394         void cleanupOutdated();
395
396 // called from main thread
397         void cleanupOutdatedTimer();
398         void timeUpdated();
399         void DVBChannelAdded(eDVBChannel*);
400         void DVBChannelStateChanged(iDVBChannel*);
401         void DVBChannelRunning(iDVBChannel *);
402
403 // just for internal use to query events in temporary cache maps (when cache is running)
404         RESULT startTimeQueryTemp(const eServiceReference &service, time_t begin=-1, int minutes=-1);
405         RESULT lookupEventIdTemp(const eServiceReference &service, int event_id, const cacheData *&);
406         RESULT lookupEventTimeTemp(const eServiceReference &service, time_t, const cacheData *&, int direction=0);
407
408         __u8 *allocateSectionBuffer();
409
410         timeMap::iterator m_timemap_cursor, m_timemap_end;
411         int currentQueryTsidOnid; // needed for getNextTimeEntry.. only valid until next startTimeQuery call
412 #else
413         eEPGCache();
414         ~eEPGCache();
415 #endif // SWIG
416 public:
417         static eEPGCache *getInstance() { return instance; }
418 #ifndef SWIG
419         eEPGCache();
420         ~eEPGCache();
421
422 #ifdef ENABLE_PRIVATE_EPG
423         void PMTready(eDVBServicePMTHandler *pmthandler);
424 #else
425         void PMTready(eDVBServicePMTHandler *pmthandler) {}
426 #endif
427
428 #endif
429         void load();
430         void save();
431
432         // must be called once!
433         void setCacheFile(const char *filename);
434         void setCacheTimespan(int days);
435         void setOutdatedEPGTimespan(int hours);
436
437         // called from main thread
438         inline void Lock();
439         inline void Unlock();
440
441         enum {
442                 SIMILAR_BROADCASTINGS_SEARCH,
443                 EXAKT_TITLE_SEARCH,
444                 PARTIAL_TITLE_SEARCH,
445                 PARTIAL_DESCRIPTION_SEARCH
446         };
447         enum {
448                 CASE_CHECK,
449                 NO_CASE_CHECK
450         };
451         PyObject *lookupEvent(SWIG_PYOBJECT(ePyObject) list);
452         PyObject *search(SWIG_PYOBJECT(ePyObject));
453
454         // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock
455         // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description )
456         SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
457         SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
458 };
459
460 #ifndef SWIG
461 inline void eEPGCache::Lock()
462 {
463         pthread_mutex_lock(&cache_lock);
464 }
465
466 inline void eEPGCache::Unlock()
467 {
468         pthread_mutex_unlock(&cache_lock);
469 }
470 #endif
471
472 #endif