4.5.0r6
[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 #include <vector>
10 #include <list>
11 #include <queue>
12 #if defined(__GXX_EXPERIMENTAL_CXX0X__)
13 #include <unordered_map>
14 #include <unordered_set>
15 #else
16 #include <ext/hash_map>
17 #include <ext/hash_set>
18 #endif
19
20 #include <errno.h>
21 #include <features.h>
22
23 #include <lib/dvb/idvb.h>
24 #include <lib/dvb/demux.h>
25 #include <lib/dvb/dvbtime.h>
26 #include <lib/base/ebase.h>
27 #include <lib/base/thread.h>
28 #include <lib/base/message.h>
29 #include <lib/service/event.h>
30 #include <lib/python/python.h>
31
32 #define CLEAN_INTERVAL 60000    //  1 min
33 #define UPDATE_INTERVAL 3600000  // 60 min
34 #define ZAP_DELAY 2000          // 2 sek
35
36 #define HILO(x) (x##_hi << 8 | x##_lo)
37
38 class cacheData;
39 struct eServiceReferenceDVB;
40 class eDVBServicePMTHandler;
41
42 struct uniqueEPGKey
43 {
44         int sid, onid, tsid, dvbnamespace;
45         uniqueEPGKey( const eServiceReference &ref )
46                 :sid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getServiceID().get() : -1 )
47                 ,onid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getOriginalNetworkID().get() : -1 )
48                 ,tsid( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getTransportStreamID().get() : -1 )
49                 ,dvbnamespace( ref.type != eServiceReference::idInvalid ? ((eServiceReferenceDVB&)ref).getDVBNamespace().get() : -1 )
50         {
51                 filterNamespace();
52         }
53         uniqueEPGKey()
54                 :sid(-1), onid(-1), tsid(-1), dvbnamespace(-1)
55         {
56         }
57         uniqueEPGKey( int sid, int onid, int tsid, int dvbnamespace )
58                 :sid(sid), onid(onid), tsid(tsid), dvbnamespace(dvbnamespace)
59         {
60                 filterNamespace();
61         }
62         uniqueEPGKey( const eDVBChannelID &chid)
63                 :sid(-1), onid(chid.original_network_id.get()), tsid(chid.transport_stream_id.get()), dvbnamespace(chid.dvbnamespace.get())
64         {
65         }
66         void filterNamespace()
67         {
68                 if ((dvbnamespace & 0xFFFF0000) == 0xEEEE0000)
69                         dvbnamespace &= 0xFFFF0000;
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
181         pthread_mutex_t m_mutex;
182         pthread_cond_t m_cond;
183         std::queue<struct Message> m_queue;
184         int m_running;
185
186         std::map<uniqueEPGKey, int> m_locked_services;
187
188         void gotMessage(const Message &message);
189         void thread();
190 public:
191         EPGDBThread(eEPGCache *cache);
192         /* this functions are called from main thread */
193         void sendData(const uniqueEPGKey &service, const __u8 *data, int source);
194         void lockService(const uniqueEPGKey &service);
195         void unlockService(const uniqueEPGKey &service, bool first=false);
196         void shutdown();
197         void start();
198         void cleanupOutdated();
199 };
200
201 #endif
202
203 class cachestate
204 {
205 public:
206         int state;
207         uint16_t tsid;
208         uint16_t onid;
209         uint32_t dvbnamespace;
210         int seconds; /* deferred seconds */
211         enum { started, stopped, aborted, deferred, load_finished, save_finished };
212         ~cachestate()
213         {
214         }
215 #ifdef SWIG
216 private:
217 #endif
218         cachestate(const cachestate &s)
219                 :state(s.state), tsid(s.tsid), onid(s.onid), dvbnamespace(s.dvbnamespace), seconds(s.seconds)
220         {
221         }
222         cachestate(int state)
223                 :state(state)
224         {
225         }
226         cachestate(int state, const uniqueEPGKey &chid, int seconds=0)
227                 :state(state), tsid(chid.tsid), onid(chid.onid), dvbnamespace(chid.dvbnamespace), seconds(seconds)
228         {
229         }
230 };
231
232 class QSqlQuery;
233
234 class eEPGCache: public iObject, public eMainloop_native, private eThread, public Object
235 {
236         E_DECLARE_PRIVATE(eEPGCache)
237
238 #ifndef SWIG
239         DECLARE_REF(eEPGCache)
240         struct channel_data: public sigc::trackable
241         {
242                 pthread_mutex_t channel_active;
243                 channel_data(eEPGCache*);
244                 eEPGCache *cache;
245                 ePtr<eTimer> abortTimer, zapTimer;
246                 int prevChannelState;
247                 int state;
248                 __u8 isRunning, haveData;
249                 bool m_mustSendCacheStopped;
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 struct channel_data;
356         friend class EPGDBThread;
357         static eEPGCache *instance;
358
359         bool execStmt(QSqlQuery &stmt);
360
361         ePtr<eTimer> cleanTimer;
362         ePtr<eTimer> stopTransaktionTimer;
363
364 //      ePtr<eTimer> flushToDBTimer;
365         std::map<iDVBChannel*, channel_data*> m_knownChannels;
366         ePtr<eConnection> m_chanAddedConn;
367
368         eventCache eventDB;
369         updateMap channelLastUpdated;
370         pulledDBDataMap pulledData;
371         static pthread_mutex_t cache_lock, channel_map_lock;
372
373 #ifdef ENABLE_PRIVATE_EPG
374         contentMaps content_time_tables;
375 #endif
376
377         int m_running;
378         int m_outdated_epg_timespan;
379         std::string m_filename;
380
381         EPGDBThread m_db_thread;
382         __u8 *m_next_section_buffer;
383
384 // called from epgcache thread
385         void loadInternal();
386         void saveInternal(bool do_cleanup=false);
387
388         void thread();  // thread function
389         bool copyDatabase(void *memorydb, const std::string &filename, bool save, bool do_cleanup=false);
390 #ifdef ENABLE_PRIVATE_EPG
391         void privateSectionRead(const uniqueEPGKey &, const __u8 *);
392 #endif
393         void sectionRead(const __u8 *data, int source, channel_data *channel);
394         bool hasExternalData(const uniqueEPGKey &service);
395         void gotMessage(const Message &message);
396         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
397
398 // called from db thread
399         void processData(const struct uniqueEPGKey &service, const __u8 *data, int source);
400         void pushToDB(const uniqueEPGKey &);
401         void pullFromDB(const uniqueEPGKey &);
402         void cleanupAfterPullPush();
403         void cleanupOutdated();
404
405 // called from main thread
406         void cleanupOutdatedTimer();
407         void timeUpdated();
408         void DVBChannelAdded(eDVBChannel*);
409         void DVBChannelStateChanged(iDVBChannel*);
410         void DVBChannelRunning(iDVBChannel *);
411
412 // just for internal use to query events in temporary cache maps (when cache is running)
413         RESULT startTimeQueryTemp(const eServiceReference &service, time_t begin=-1, int minutes=-1);
414         RESULT lookupEventIdTemp(const eServiceReference &service, int event_id, const cacheData *&);
415         RESULT lookupEventTimeTemp(const eServiceReference &service, time_t, const cacheData *&, int direction=0);
416
417         __u8 *allocateSectionBuffer();
418
419         timeMap::iterator m_timemap_cursor, m_timemap_end;
420         int currentQueryTsidOnid; // needed for getNextTimeEntry.. only valid until next startTimeQuery call
421 #else
422         eEPGCache();
423         ~eEPGCache();
424 #endif // SWIG
425 public:
426         static eEPGCache *getInstance() { return instance; }
427         static uint32_t getStringHash(std::string text);
428 #ifndef SWIG
429         eEPGCache();
430         ~eEPGCache();
431
432         std::vector< ePtr<eServiceEvent> > lookupEvents(const eServiceReference &sref, int startTime, int minutes=-1);
433 #ifdef ENABLE_PRIVATE_EPG
434         void PMTready(eDVBServicePMTHandler *pmthandler);
435 #else
436         void PMTready(eDVBServicePMTHandler *pmthandler) {}
437 #endif
438
439 #endif
440         void load();
441         void save();
442
443         void applyDbBugfix20161008();
444         void createUpdateTriggers();
445
446         // must be called once!
447         void setCacheFile(const char *filename);
448         void setCacheTimespan(int days);
449         void setOutdatedEPGTimespan(int hours);
450
451         // called from main thread
452         inline void Lock();
453         inline void Unlock();
454
455         enum {
456                 SIMILAR_BROADCASTINGS_SEARCH,
457                 EXACT_TITLE_SEARCH,
458                 EXAKT_TITLE_SEARCH = EXACT_TITLE_SEARCH,
459                 PARTIAL_TITLE_SEARCH,
460                 PARTIAL_DESCRIPTION_SEARCH,
461                 PARTIAL_EXTENDED_DESCRIPTION_SEARCH,
462         };
463         enum {
464                 CASE_CHECK,
465                 NO_CASE_CHECK
466         };
467         PyObject *lookupEvent(SWIG_PYOBJECT(ePyObject) list);
468         PyObject *search(SWIG_PYOBJECT(ePyObject));
469
470         // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock
471         // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description )
472         SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
473         SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
474
475         eSignal1<void, boost::any> cacheState; // sent when data collecting has started/stopped/aborted/deferred
476 };
477
478 #ifndef SWIG
479 inline void eEPGCache::Lock()
480 {
481         pthread_mutex_lock(&cache_lock);
482 }
483
484 inline void eEPGCache::Unlock()
485 {
486         pthread_mutex_unlock(&cache_lock);
487 }
488 #endif
489
490 #endif