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