implement interface for query epg
[vuplus_dvbapp] / lib / dvb / epgcache.h
1 #ifndef __epgcache_h_
2 #define __epgcache_h_
3
4 #include <vector>
5 #include <list>
6 #include <ext/hash_map>
7 #include <ext/hash_set>
8
9 #include <errno.h>
10
11 #include <lib/dvb/eit.h>
12 #include <lib/dvb/lowlevel/eit.h>
13 #include <lib/dvb/idvb.h>
14 #include <lib/dvb/demux.h>
15 #include <lib/dvb/dvbtime.h>
16 #include <lib/base/ebase.h>
17 #include <lib/base/thread.h>
18 #include <lib/base/message.h>
19 #include <lib/service/event.h>
20
21 #define CLEAN_INTERVAL 60000    //  1 min
22 #define UPDATE_INTERVAL 3600000  // 60 min
23 #define ZAP_DELAY 2000          // 2 sek
24
25 #define HILO(x) (x##_hi << 8 | x##_lo)
26
27 class eventData;
28 class eServiceReferenceDVB;
29
30 struct uniqueEPGKey
31 {
32         int sid, onid, tsid;
33         uniqueEPGKey( const eServiceReferenceDVB &ref )
34                 :sid( ref.type != eServiceReference::idInvalid ? ref.getServiceID().get() : -1 )
35                 ,onid( ref.type != eServiceReference::idInvalid ? ref.getOriginalNetworkID().get() : -1 )
36                 ,tsid( ref.type != eServiceReference::idInvalid ? ref.getTransportStreamID().get() : -1 )
37         {
38         }
39         uniqueEPGKey()
40                 :sid(-1), onid(-1), tsid(-1)
41         {
42         }
43         uniqueEPGKey( int sid, int onid, int tsid )
44                 :sid(sid), onid(onid), tsid(tsid)
45         {
46         }
47         bool operator <(const uniqueEPGKey &a) const
48         {
49                 return memcmp( &sid, &a.sid, sizeof(int)*3)<0;
50         }
51         operator bool() const
52         { 
53                 return !(sid == -1 && onid == -1 && tsid == -1); 
54         }
55         bool operator==(const uniqueEPGKey &a) const
56         {
57                 return !memcmp( &sid, &a.sid, sizeof(int)*3);
58         }
59         struct equal
60         {
61                 bool operator()(const uniqueEPGKey &a, const uniqueEPGKey &b) const
62                 {
63                         return !memcmp( &a.sid, &b.sid, sizeof(int)*3);
64                 }
65         };
66 };
67
68 //eventMap is sorted by event_id
69 #define eventMap std::map<__u16, eventData*>
70 //timeMap is sorted by beginTime
71 #define timeMap std::map<time_t, eventData*>
72
73 #define channelMapIterator std::map<iDVBChannel*, channel_data*>::iterator
74 #define updateMap std::map<eDVBChannelID, time_t>
75
76 struct hash_uniqueEPGKey
77 {
78         inline size_t operator()( const uniqueEPGKey &x) const
79         {
80                 return (x.onid << 16) | x.tsid;
81         }
82 };
83
84 #define tidMap std::set<__u32>
85 #if defined(__GNUC__) && ((__GNUC__ == 3 && __GNUC_MINOR__ >= 1) || __GNUC__ == 4 )  // check if gcc version >= 3.1
86         #define eventCache __gnu_cxx::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal>
87 #else // for older gcc use following
88         #define eventCache std::hash_map<uniqueEPGKey, std::pair<eventMap, timeMap>, hash_uniqueEPGKey, uniqueEPGKey::equal >
89 #endif
90
91 #define descriptorPair std::pair<int,__u8*>
92 #define descriptorMap std::map<__u32, descriptorPair >
93
94 class eventData
95 {
96         friend class eEPGCache;
97 private:
98         __u8* EITdata;
99         __u8 ByteSize;
100         static descriptorMap descriptors;
101         static __u8 data[4108];
102 public:
103         __u8 type;
104         static int CacheSize;
105         static void load(FILE *);
106         static void save(FILE *);
107         eventData(const eit_event_struct* e, int size, int type);
108         ~eventData();
109         const eit_event_struct* get() const;
110         operator const eit_event_struct*() const
111         {
112                 return get();
113         }
114         int getEventID()
115         {
116                 return (EITdata[0] << 8) | EITdata[1];
117         }
118         time_t getStartTime()
119         {
120                 return parseDVBtime(EITdata[2], EITdata[3], EITdata[4], EITdata[5], EITdata[6]);
121         }
122         int getDuration()
123         {
124                 return fromBCD(EITdata[7])*3600+fromBCD(EITdata[8])*60+fromBCD(EITdata[9]);
125         }
126 };
127
128 class eEPGCache: public eMainloop, private eThread, public Object
129 {
130         DECLARE_REF(eEPGCache)
131         struct channel_data: public Object
132         {
133                 channel_data(eEPGCache*);
134                 eEPGCache *cache;
135                 eTimer abortTimer, zapTimer;
136                 __u8 state, isRunning, haveData, can_delete;
137                 ePtr<eDVBChannel> channel;
138                 ePtr<eConnection> m_stateChangedConn, m_NowNextConn, m_ScheduleConn, m_ScheduleOtherConn;
139                 ePtr<iDVBSectionReader> m_NowNextReader, m_ScheduleReader, m_ScheduleOtherReader;
140                 tidMap seenSections[3], calcedSections[3];
141                 void readData(const __u8 *data);
142                 void startChannel();
143                 void startEPG();
144                 bool finishEPG();
145                 void abortEPG();
146                 void abortNonAvail();
147         };
148 public:
149         enum {NOWNEXT=1, SCHEDULE=2, SCHEDULE_OTHER=4};
150         struct Message
151         {
152                 enum
153                 {
154                         flush,
155                         startChannel,
156                         leaveChannel,
157                         pause,
158                         restart,
159                         updated,
160                         isavail,
161                         quit,
162                         timeChanged
163                 };
164                 int type;
165                 iDVBChannel *channel;
166                 uniqueEPGKey service;
167                 union {
168                         int err;
169                         time_t time;
170                         bool avail;
171                 };
172                 Message()
173                         :type(0), time(0) {}
174                 Message(int type)
175                         :type(type) {}
176                 Message(int type, bool b)
177                         :type(type), avail(b) {}
178                 Message(int type, iDVBChannel *channel, int err=0)
179                         :type(type), channel(channel), err(err) {}
180                 Message(int type, const eServiceReferenceDVB& service, int err=0)
181                         :type(type), service(service), err(err) {}
182                 Message(int type, time_t time)
183                         :type(type), time(time) {}
184         };
185         eFixedMessagePump<Message> messages;
186 private:
187         friend class channel_data;
188         static eEPGCache *instance;
189
190         eTimer cleanTimer;
191         std::map<iDVBChannel*, channel_data*> m_knownChannels;
192         ePtr<eConnection> m_chanAddedConn;
193
194         eventCache eventDB;
195         updateMap channelLastUpdated;
196         static pthread_mutex_t cache_lock, channel_map_lock;
197
198         void thread();  // thread function
199
200 // called from epgcache thread
201         void save();
202         void load();
203         void sectionRead(const __u8 *data, int source, channel_data *channel);
204         void gotMessage(const Message &message);
205         void flushEPG(const uniqueEPGKey & s=uniqueEPGKey());
206         void cleanLoop();
207
208 // called from main thread
209         void timeUpdated();
210         void DVBChannelAdded(eDVBChannel*);
211         void DVBChannelStateChanged(iDVBChannel*);
212         void DVBChannelRunning(iDVBChannel *);
213
214         timeMap::iterator m_timemap_cursor, m_timemap_end;
215 public:
216         static RESULT getInstance(ePtr<eEPGCache> &ptr);
217         eEPGCache();
218         ~eEPGCache();
219
220         // called from main thread
221         inline void Lock();
222         inline void Unlock();
223
224         // at moment just for one service..
225         inline RESULT startTimeQuery(const eServiceReferenceDVB &service, time_t begin=-1, int minutes=-1);
226
227         // eventData's are plain entrys out of the cache.. it's not safe to use them after cache unlock
228         // but its faster in use... its not allowed to delete this pointers via delete or free..
229         RESULT lookupEvent(const eServiceReferenceDVB &service, int event_id, const eventData *&);
230         RESULT lookupEvent(const eServiceReferenceDVB &service, time_t , const eventData *&);
231         RESULT getNextTimeEntry(const eventData *&);
232
233         // eit_event_struct's are plain dvb eit_events .. it's not safe to use them after cache unlock
234         // its not allowed to delete this pointers via delete or free..
235         RESULT lookupEvent(const eServiceReferenceDVB &service, int event_id, const eit_event_struct *&);
236         RESULT lookupEvent(const eServiceReferenceDVB &service, time_t , const eit_event_struct *&);
237         RESULT getNextTimeEntry(const eit_event_struct *&);
238
239         // Event's are parsed epg events.. it's safe to use them after cache unlock
240         // after use this Events must be deleted (memleaks)
241         RESULT lookupEvent(const eServiceReferenceDVB &service, int event_id, Event* &);
242         RESULT lookupEvent(const eServiceReferenceDVB &service, time_t, Event* &);
243         RESULT getNextTimeEntry(Event *&);
244
245         // eServiceEvent are parsed epg events.. it's safe to use them after cache unlock
246         // for use from python ( members: m_start_time, m_duration, m_short_description, m_extended_description )
247         RESULT lookupEvent(const eServiceReferenceDVB &service, int event_id, ePtr<eServiceEvent> &);
248         RESULT lookupEvent(const eServiceReferenceDVB &service, time_t , ePtr<eServiceEvent> &);
249         RESULT getNextTimeEntry(ePtr<eServiceEvent> &);
250 };
251
252 TEMPLATE_TYPEDEF(ePtr<eEPGCache>,eEPGCachePtr);
253
254 inline void eEPGCache::Lock()
255 {
256         pthread_mutex_lock(&cache_lock);
257 }
258
259 inline void eEPGCache::Unlock()
260 {
261         pthread_mutex_unlock(&cache_lock);
262 }
263
264 #endif