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