4.2.1r2
[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 class eEPGCache;
148
149 class EPGDBThread: public eMainloop_native, private eThread, public Object
150 {
151         struct Message
152         {
153                 enum { unknown, process_data, shutdown, lock_service, unlock_service, unlock_first, cleanup_outdated };
154                 Message()
155                         :type(unknown)
156                 {
157                 }
158                 Message(const Message &msg)
159                         :type(msg.type), data(msg.data), service(msg.service), source(msg.source)
160                 {
161                 }
162                 Message(const struct uniqueEPGKey &service, int type)
163                         :type(type), service(service)
164                 {
165                 }
166                 Message(const struct uniqueEPGKey &service, const __u8 *data, int source)
167                         :type(process_data), data(data), service(service), source(source)
168                 {
169                 }
170                 Message(int type)
171                         :type(type)
172                 {
173                 }
174                 int type;
175                 const __u8 *data;
176                 struct uniqueEPGKey service;
177                 int source;
178         };
179         eEPGCache *m_epg_cache;
180         QSqlDatabase &m_db_rw;
181
182         pthread_mutex_t m_mutex;
183         pthread_cond_t m_cond;
184         std::queue<struct Message> m_queue;
185         int m_running;
186
187         std::map<uniqueEPGKey, int> m_locked_services;
188
189         void gotMessage(const Message &message);
190         void thread();
191 public:
192         EPGDBThread(eEPGCache *cache, QSqlDatabase &db);
193         /* this functions are called from main thread */
194         void sendData(const uniqueEPGKey &service, const __u8 *data, int source);
195         void lockService(const uniqueEPGKey &service);
196         void unlockService(const uniqueEPGKey &service, bool first=false);
197         void shutdown();
198         void start();
199         void cleanupOutdated();
200 };
201
202 #endif
203
204 class cachestate
205 {
206 public:
207         int state;
208         uint16_t tsid;
209         uint16_t onid;
210         uint32_t dvbnamespace;
211         int seconds; /* deferred seconds */
212         enum { started, stopped, aborted, deferred };
213         uint16_t getTsid() const { return tsid; }
214         ~cachestate()
215         {
216         }
217 #ifdef SWIG
218 private:
219 #endif
220         cachestate(const cachestate &s)
221                 :state(s.state), tsid(s.tsid), onid(s.onid), dvbnamespace(s.dvbnamespace), seconds(s.seconds)
222         {
223         }
224         cachestate(int state, const eDVBChannelID &chid, int seconds=0)
225                 :state(state), tsid(chid.transport_stream_id.get()), onid(chid.original_network_id.get()), dvbnamespace(chid.dvbnamespace.get()), seconds(seconds)
226         {
227         }
228 };
229
230 class eEPGCache: public iObject, public eMainloop_native, private eThread, public Object
231 {
232 #ifndef SWIG
233         DECLARE_REF(eEPGCache)
234         struct channel_data: public sigc::trackable
235         {
236                 pthread_mutex_t channel_active;
237                 channel_data(eEPGCache*);
238                 eEPGCache *cache;
239                 ePtr<eTimer> abortTimer, zapTimer;
240                 int prevChannelState;
241                 int state;
242                 __u8 isRunning, haveData;
243                 ePtr<eDVBChannel> channel;
244                 ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn, m_ViasatConn;
245                 ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader, m_ViasatReader;
246                 tidMap seenSections[4], calcedSections[4];
247                 std::set<uniqueEPGKey> m_seen_services;
248 #ifdef ENABLE_PRIVATE_EPG
249                 ePtr<eTimer> startPrivateTimer;
250                 int m_PrevVersion;
251                 int m_PrivatePid;
252                 uniqueEPGKey m_PrivateService;
253                 ePtr<eConnection> m_PrivateConn;
254                 ePtr<iDVBSectionReader> m_PrivateReader;
255                 std::set<__u8> seenPrivateSections;
256                 void readPrivateData(const __u8 *data, int len);
257                 void startPrivateReader();
258 #endif
259 #ifdef ENABLE_MHW_EPG
260                 std::vector<mhw_channel_name_t> m_channels;
261                 std::map<__u8, mhw_theme_name_t> m_themes;
262                 std::map<__u32, mhw_title_t> m_titles;
263                 std::multimap<__u32, __u32> m_program_ids;
264                 ePtr<eConnection> m_MHWConn, m_MHWConn2;
265                 ePtr<iDVBSectionReader> m_MHWReader, m_MHWReader2;
266                 eDVBSectionFilterMask m_MHWFilterMask, m_MHWFilterMask2;
267                 ePtr<eTimer> m_MHWTimeoutTimer;
268                 __u16 m_mhw2_channel_pid, m_mhw2_title_pid, m_mhw2_summary_pid;
269                 bool m_MHWTimeoutet;
270                 void MHWTimeout() { m_MHWTimeoutet=true; }
271                 void readMHWData(const __u8 *data);
272                 void readMHWData2(const __u8 *data);
273                 void startMHWReader(__u16 pid, __u8 tid);
274                 void startMHWReader2(__u16 pid, __u8 tid, int ext=-1);
275                 void startTimeout(int msek);
276                 bool checkTimeout() { return m_MHWTimeoutet; }
277                 void cleanup();
278                 __u8 *delimitName( __u8 *in, __u8 *out, int len_in );
279                 void timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time);
280                 void timeMHW2DVB( int minutes, u_char *return_time);
281                 void timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time);
282                 void storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, const std::string &sumText, const __u8 *data);
283 #endif
284                 void readData(const __u8 *data, int len);
285                 void readDataViasat(const __u8 *data, int len);
286                 void startChannel();
287                 void startEPG();
288                 bool finishEPG();
289                 void abortEPG();
290                 void abortNonAvail();
291                 bool isCaching();
292         };
293         bool FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service);
294 public:
295         enum {PRIVATE=0, NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4
296 #ifdef ENABLE_MHW_EPG
297         ,MHW=8
298 #endif
299         ,VIASAT=16
300         };
301         struct Message
302         {
303                 enum
304                 {
305                         flush,
306                         startChannel,
307                         leaveChannel,
308                         load,
309                         save,
310                         cacheStarted,
311                         cacheStopped,
312                         cacheDeferred,
313                         quit,
314                         got_private_pid,
315                         got_mhw2_channel_pid,
316                         got_mhw2_title_pid,
317                         got_mhw2_summary_pid,
318                 };
319                 int type;
320                 iDVBChannel *channel;
321                 uniqueEPGKey service;
322                 union {
323                         int err;
324                         time_t time;
325                         bool avail;
326                         int pid;
327                 };
328                 Message()
329                         :type(0), time(0) {}
330                 Message(int type)
331                         :type(type) {}
332                 Message(int type, bool b)
333                         :type(type), avail(b) {}
334                 Message(int type, iDVBChannel *channel, int err=0)
335                         :type(type), channel(channel), err(err) {}
336                 Message(int type, const eServiceReference& service, int err=0)
337                         :type(type), service(service), err(err) {}
338                 Message(int type, time_t time)
339                         :type(type), time(time) {}
340         };
341         eFixedMessagePump<Message> messages;
342         eFixedMessagePump<Message> thread_messages;
343 private:
344         friend class channel_data;
345         friend class EPGDBThread;
346         static eEPGCache *instance;
347
348         ePtr<eTimer> cleanTimer;
349         ePtr<eTimer> stopTransaktionTimer;
350
351 //      ePtr<eTimer> flushToDBTimer;
352         std::map<iDVBChannel*, channel_data*> m_knownChannels;
353         ePtr<eConnection> m_chanAddedConn;
354
355         eventCache eventDB;
356         updateMap channelLastUpdated;
357         pulledDBDataMap pulledData;
358         static pthread_mutex_t cache_lock, channel_map_lock;
359
360 #ifdef ENABLE_PRIVATE_EPG
361         contentMaps content_time_tables;
362 #endif
363
364         int m_running;
365         int m_outdated_epg_timespan;
366         char m_filename[1024];
367
368         QSqlDatabase m_db_rw, m_db_ro;
369         QSqlQuery m_stmt_service_id_q;
370         QSqlQuery m_stmt_service_add;
371
372         QSqlQuery m_stmt_event_id_q;
373         QSqlQuery m_stmt_event_add;
374         QSqlQuery m_stmt_event_update;
375         QSqlQuery m_stmt_event_delete;
376         QSqlQuery m_stmt_event_cleanup_outdated;
377
378         QSqlQuery m_stmt_event_service_q;
379
380         QSqlQuery m_stmt_title_id_q;
381         QSqlQuery m_stmt_title_add;
382
383         QSqlQuery m_stmt_short_description_id_q;
384         QSqlQuery m_stmt_short_description_add;
385
386         QSqlQuery m_stmt_extended_description_id_q;
387         QSqlQuery m_stmt_extended_description_add;
388
389         QSqlQuery m_stmt_data_id_q;
390         QSqlQuery m_stmt_data_add;
391         QSqlQuery m_stmt_data_update;
392         QSqlQuery m_stmt_data_delete;
393
394         // queries for public access
395         QSqlQuery m_stmt_lookup_begin_time;
396         QSqlQuery m_stmt_lookup_event_id;
397         QSqlQuery m_stmt_lookup_now;
398         QSqlQuery m_stmt_lookup_before;
399
400         QSqlQuery m_stmt_lookup_all;
401         QSqlQuery m_stmt_lookup_end_time;
402
403         EPGDBThread m_db_thread;
404         __u8 *m_next_section_buffer;
405
406 // called from epgcache thread
407         void loadInternal();
408         void saveInternal();
409
410         void thread();  // thread function
411         bool copyDatabase(QSqlDatabase *memorydb, char* filename, bool save);
412 #ifdef ENABLE_PRIVATE_EPG
413         void privateSectionRead(const uniqueEPGKey &, const __u8 *);
414 #endif
415         void sectionRead(const __u8 *data, int source, channel_data *channel);
416         void gotMessage(const Message &message);
417         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
418
419 // called from db thread
420         void processData(const struct uniqueEPGKey &service, const __u8 *data, int source);
421         void pushToDB(const uniqueEPGKey &);
422         void pullFromDB(const uniqueEPGKey &);
423         void cleanupAfterPullPush();
424         void cleanupOutdated();
425
426 // called from main thread
427         void cleanupOutdatedTimer();
428         void timeUpdated();
429         void DVBChannelAdded(eDVBChannel*);
430         void DVBChannelStateChanged(iDVBChannel*);
431         void DVBChannelRunning(iDVBChannel *);
432
433 // just for internal use to query events in temporary cache maps (when cache is running)
434         RESULT startTimeQueryTemp(const eServiceReference &service, time_t begin=-1, int minutes=-1);
435         RESULT lookupEventIdTemp(const eServiceReference &service, int event_id, const cacheData *&);
436         RESULT lookupEventTimeTemp(const eServiceReference &service, time_t, const cacheData *&, int direction=0);
437
438         __u8 *allocateSectionBuffer();
439
440         timeMap::iterator m_timemap_cursor, m_timemap_end;
441         int currentQueryTsidOnid; // needed for getNextTimeEntry.. only valid until next startTimeQuery call
442 #else
443         eEPGCache();
444         ~eEPGCache();
445 #endif // SWIG
446 public:
447         static eEPGCache *getInstance() { return instance; }
448         static __u32 getStringHash(std::string text);
449 #ifndef SWIG
450         eEPGCache();
451         ~eEPGCache();
452
453 #ifdef ENABLE_PRIVATE_EPG
454         void PMTready(eDVBServicePMTHandler *pmthandler);
455 #else
456         void PMTready(eDVBServicePMTHandler *pmthandler) {}
457 #endif
458
459 #endif
460         void load();
461         void save();
462
463         // must be called once!
464         void setCacheFile(const char *filename);
465         void setCacheTimespan(int days);
466         void setOutdatedEPGTimespan(int hours);
467
468         // called from main thread
469         inline void Lock();
470         inline void Unlock();
471
472         enum {
473                 SIMILAR_BROADCASTINGS_SEARCH,
474                 EXAKT_TITLE_SEARCH,
475                 PARTIAL_TITLE_SEARCH,
476                 PARTIAL_DESCRIPTION_SEARCH
477         };
478         enum {
479                 CASE_CHECK,
480                 NO_CASE_CHECK
481         };
482         PyObject *lookupEvent(SWIG_PYOBJECT(ePyObject) list);
483         PyObject *search(SWIG_PYOBJECT(ePyObject));
484
485         // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock
486         // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description )
487         SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
488         SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
489
490         eSignal1<void, boost::any> cacheState; // sent when data collecting has started/stopped/aborted/deferred
491 };
492
493 #ifndef SWIG
494 inline void eEPGCache::Lock()
495 {
496         pthread_mutex_lock(&cache_lock);
497 }
498
499 inline void eEPGCache::Unlock()
500 {
501         pthread_mutex_unlock(&cache_lock);
502 }
503 #endif
504
505 #endif