enigma2: 4.3.1r5
[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 eEPGCache: public iObject, public eMainloop_native, private eThread, public Object
233 {
234         E_DECLARE_PRIVATE(eEPGCache)
235
236 #ifndef SWIG
237         DECLARE_REF(eEPGCache)
238         struct channel_data: public sigc::trackable
239         {
240                 pthread_mutex_t channel_active;
241                 channel_data(eEPGCache*);
242                 eEPGCache *cache;
243                 ePtr<eTimer> abortTimer, zapTimer;
244                 int prevChannelState;
245                 int state;
246                 __u8 isRunning, haveData;
247                 ePtr<eDVBChannel> channel;
248                 ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn, m_ViasatConn;
249                 ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader, m_ViasatReader;
250                 tidMap seenSections[4], calcedSections[4];
251                 std::set<uniqueEPGKey> m_seen_services;
252                 std::set<uniqueEPGKey> m_skipped_services;
253 #ifdef ENABLE_PRIVATE_EPG
254                 ePtr<eTimer> startPrivateTimer;
255                 int m_PrevVersion;
256                 int m_PrivatePid;
257                 uniqueEPGKey m_PrivateService;
258                 ePtr<eConnection> m_PrivateConn;
259                 ePtr<iDVBSectionReader> m_PrivateReader;
260                 std::set<__u8> seenPrivateSections;
261                 void readPrivateData(const __u8 *data, int len);
262                 void startPrivateReader();
263 #endif
264 #ifdef ENABLE_MHW_EPG
265                 std::vector<mhw_channel_name_t> m_channels;
266                 std::map<__u8, mhw_theme_name_t> m_themes;
267                 std::map<__u32, mhw_title_t> m_titles;
268                 std::multimap<__u32, __u32> m_program_ids;
269                 ePtr<eConnection> m_MHWConn, m_MHWConn2;
270                 ePtr<iDVBSectionReader> m_MHWReader, m_MHWReader2;
271                 eDVBSectionFilterMask m_MHWFilterMask, m_MHWFilterMask2;
272                 ePtr<eTimer> m_MHWTimeoutTimer;
273                 __u16 m_mhw2_channel_pid, m_mhw2_title_pid, m_mhw2_summary_pid;
274                 bool m_MHWTimeoutet;
275                 void MHWTimeout() { m_MHWTimeoutet=true; }
276                 void readMHWData(const __u8 *data);
277                 void readMHWData2(const __u8 *data);
278                 void startMHWReader(__u16 pid, __u8 tid);
279                 void startMHWReader2(__u16 pid, __u8 tid, int ext=-1);
280                 void startTimeout(int msek);
281                 bool checkTimeout() { return m_MHWTimeoutet; }
282                 void cleanup();
283                 __u8 *delimitName( __u8 *in, __u8 *out, int len_in );
284                 void timeMHW2DVB( u_char hours, u_char minutes, u_char *return_time);
285                 void timeMHW2DVB( int minutes, u_char *return_time);
286                 void timeMHW2DVB( u_char day, u_char hours, u_char minutes, u_char *return_time);
287                 void storeTitle(std::map<__u32, mhw_title_t>::iterator itTitle, const std::string &sumText, const __u8 *data);
288 #endif
289                 void readData(const __u8 *data, int len);
290                 void readDataViasat(const __u8 *data, int len);
291                 void startChannel();
292                 void startEPG();
293                 bool finishEPG();
294                 void abortEPG();
295                 void abortNonAvail();
296                 bool isCaching();
297         };
298         bool FixOverlapping(std::pair<eventMap,timeMap> &servicemap, time_t TM, int duration, const timeMap::iterator &tm_it, const uniqueEPGKey &service);
299 public:
300         enum {PRIVATE=0, NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4
301 #ifdef ENABLE_MHW_EPG
302         ,MHW=8
303 #endif
304         ,VIASAT=16
305         };
306         struct Message
307         {
308                 enum
309                 {
310                         flush,
311                         startChannel,
312                         leaveChannel,
313                         load,
314                         save,
315                         cacheStarted,
316                         cacheStopped,
317                         cacheDeferred,
318                         quit,
319                         got_private_pid,
320                         got_mhw2_channel_pid,
321                         got_mhw2_title_pid,
322                         got_mhw2_summary_pid,
323                         loadFinished,
324                         saveFinished
325                 };
326                 int type;
327                 iDVBChannel *channel;
328                 uniqueEPGKey service;
329                 union {
330                         int err;
331                         time_t time;
332                         bool avail;
333                         int pid;
334                 };
335                 Message()
336                         :type(0), time(0) {}
337                 Message(int type)
338                         :type(type) {}
339                 Message(int type, bool b)
340                         :type(type), avail(b) {}
341                 Message(int type, iDVBChannel *channel)
342                         :type(type), channel(channel) {}
343                 Message(int type, iDVBChannel *channel, int err);
344                 Message(int type, const eServiceReference& service, int err=0)
345                         :type(type), service(service), err(err) {}
346                 Message(int type, time_t time)
347                         :type(type), time(time) {}
348         };
349         eFixedMessagePump<Message> messages;
350         eFixedMessagePump<Message> thread_messages;
351 private:
352         friend struct channel_data;
353         friend class EPGDBThread;
354         static eEPGCache *instance;
355
356         ePtr<eTimer> cleanTimer;
357         ePtr<eTimer> stopTransaktionTimer;
358
359 //      ePtr<eTimer> flushToDBTimer;
360         std::map<iDVBChannel*, channel_data*> m_knownChannels;
361         ePtr<eConnection> m_chanAddedConn;
362
363         eventCache eventDB;
364         updateMap channelLastUpdated;
365         pulledDBDataMap pulledData;
366         static pthread_mutex_t cache_lock, channel_map_lock;
367
368 #ifdef ENABLE_PRIVATE_EPG
369         contentMaps content_time_tables;
370 #endif
371
372         int m_running;
373         int m_outdated_epg_timespan;
374         char m_filename[1024];
375
376         EPGDBThread m_db_thread;
377         __u8 *m_next_section_buffer;
378
379 // called from epgcache thread
380         void loadInternal();
381         void saveInternal(bool do_cleanup=false);
382
383         void thread();  // thread function
384         bool copyDatabase(void *memorydb, char* filename, bool save, bool do_cleanup=false);
385 #ifdef ENABLE_PRIVATE_EPG
386         void privateSectionRead(const uniqueEPGKey &, const __u8 *);
387 #endif
388         void sectionRead(const __u8 *data, int source, channel_data *channel);
389         bool hasExternalData(const uniqueEPGKey &service);
390         void gotMessage(const Message &message);
391         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
392
393 // called from db thread
394         void processData(const struct uniqueEPGKey &service, const __u8 *data, int source);
395         void pushToDB(const uniqueEPGKey &);
396         void pullFromDB(const uniqueEPGKey &);
397         void cleanupAfterPullPush();
398         void cleanupOutdated();
399
400 // called from main thread
401         void cleanupOutdatedTimer();
402         void timeUpdated();
403         void DVBChannelAdded(eDVBChannel*);
404         void DVBChannelStateChanged(iDVBChannel*);
405         void DVBChannelRunning(iDVBChannel *);
406
407 // just for internal use to query events in temporary cache maps (when cache is running)
408         RESULT startTimeQueryTemp(const eServiceReference &service, time_t begin=-1, int minutes=-1);
409         RESULT lookupEventIdTemp(const eServiceReference &service, int event_id, const cacheData *&);
410         RESULT lookupEventTimeTemp(const eServiceReference &service, time_t, const cacheData *&, int direction=0);
411
412         __u8 *allocateSectionBuffer();
413
414         timeMap::iterator m_timemap_cursor, m_timemap_end;
415         int currentQueryTsidOnid; // needed for getNextTimeEntry.. only valid until next startTimeQuery call
416 #else
417         eEPGCache();
418         ~eEPGCache();
419 #endif // SWIG
420 public:
421         static eEPGCache *getInstance() { return instance; }
422         static uint32_t getStringHash(std::string text);
423 #ifndef SWIG
424         eEPGCache();
425         ~eEPGCache();
426
427 #ifdef ENABLE_PRIVATE_EPG
428         void PMTready(eDVBServicePMTHandler *pmthandler);
429 #else
430         void PMTready(eDVBServicePMTHandler *pmthandler) {}
431 #endif
432
433 #endif
434         void load();
435         void save();
436
437         void applyDbBugfix20161008();
438         void createUpdateTriggers();
439
440         // must be called once!
441         void setCacheFile(const char *filename);
442         void setCacheTimespan(int days);
443         void setOutdatedEPGTimespan(int hours);
444
445         // called from main thread
446         inline void Lock();
447         inline void Unlock();
448
449         enum {
450                 SIMILAR_BROADCASTINGS_SEARCH,
451                 EXAKT_TITLE_SEARCH,
452                 PARTIAL_TITLE_SEARCH,
453                 PARTIAL_DESCRIPTION_SEARCH
454         };
455         enum {
456                 CASE_CHECK,
457                 NO_CASE_CHECK
458         };
459         PyObject *lookupEvent(SWIG_PYOBJECT(ePyObject) list);
460         PyObject *search(SWIG_PYOBJECT(ePyObject));
461
462         // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock
463         // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description )
464         SWIG_VOID(RESULT) lookupEventId(const eServiceReference &service, int event_id, ePtr<eServiceEvent> &SWIG_OUTPUT);
465         SWIG_VOID(RESULT) lookupEventTime(const eServiceReference &service, time_t, ePtr<eServiceEvent> &SWIG_OUTPUT, int direction=0);
466
467         eSignal1<void, boost::any> cacheState; // sent when data collecting has started/stopped/aborted/deferred
468 };
469
470 #ifndef SWIG
471 inline void eEPGCache::Lock()
472 {
473         pthread_mutex_lock(&cache_lock);
474 }
475
476 inline void eEPGCache::Unlock()
477 {
478         pthread_mutex_unlock(&cache_lock);
479 }
480 #endif
481
482 #endif