trunk 20080912
[gitenigma.git] / lib / dvb / esection.cpp
blob37d5dcf87b7a31fbed97f604b471447f796162d3
1 #include <lib/dvb/esection.h>
2 #include <config.h>
4 #include <unistd.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <fcntl.h>
8 #include <errno.h>
9 #include <time.h>
10 #include <sys/ioctl.h>
12 #include <lib/base/ebase.h>
13 #include <lib/base/eerror.h>
14 #include <lib/system/elock.h>
15 #include <lib/system/info.h>
17 #if HAVE_DVB_API_VERSION < 3
18 #include <ost/dmx.h>
19 #else
20 #include <linux/dvb/dmx.h>
21 #endif
23 static pthread_mutex_t slock=
24 PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
25 ePtrList<eSection> eSection::active;
27 eSectionReader::eSectionReader()
29 handle=-1;
32 int eSectionReader::getHandle()
34 return handle;
37 void eSectionReader::close()
39 if (handle != -1)
40 ::close(handle);
41 handle=-1;
44 int eSectionReader::open(int pid, __u8 *data, __u8 *mask, __u8 *mode, int len, int _flags, const char* dmxdev)
46 tableid=data[0];
47 tableid_mask=mask[0];
48 flags=_flags;
49 #if HAVE_DVB_API_VERSION < 3
50 dmxSctFilterParams secFilterParams;
51 #else
52 dmx_sct_filter_params secFilterParams;
53 #endif
55 close();
57 handle=::open(dmxdev, O_RDWR|O_NONBLOCK);
58 // eDebug("opened handle %d", handle);
59 if (handle<0)
61 perror(dmxdev);
62 return -errno;
64 #if HAVE_DVB_API_VERSION == 3
65 else
67 if (::ioctl(handle, DMX_SET_BUFFER_SIZE, 128*1024) < 0 )
68 eDebug("DMX_SET_BUFFER_SIZE failed (%m)");
70 #endif
72 secFilterParams.pid=pid;
74 #if HAVE_DVB_API_VERSION < 3
75 memset(secFilterParams.filter.filter, 0, DMX_FILTER_SIZE);
76 memset(secFilterParams.filter.mask, 0, DMX_FILTER_SIZE);
77 #else
78 memset(&secFilterParams.filter, 0, sizeof(struct dmx_filter));
79 #endif
81 secFilterParams.timeout=0;
82 secFilterParams.flags=DMX_IMMEDIATE_START;
83 #if HAVE_DVB_API_VERSION < 3
84 if ( eSystemInfo::getInstance()->hasNegFilter() )
85 secFilterParams.flags=0;
86 #endif
87 if (flags&SECREAD_CRC)
88 secFilterParams.flags|=DMX_CHECK_CRC;
89 for (int i = 0; i < len; i++)
91 secFilterParams.filter.filter[i]=data[i];
92 secFilterParams.filter.mask[i]=mask[i];
93 #if HAVE_DVB_API_VERSION >= 3
94 secFilterParams.filter.mode[i]=mode[i];
95 #endif
98 #ifdef ESECTION_DEBUG
99 eDebugNoNewLine("%02x: ", pid);
100 for (int i=0; i<DMX_FILTER_SIZE; i++)
101 eDebugNoNewLine("%02x ", secFilterParams.filter.filter[i]);
102 eDebugNoNewLine(" (napi)\n ");
103 for (int i=0; i<DMX_FILTER_SIZE; i++)
104 eDebugNoNewLine("%02x ", secFilterParams.filter.mask[i]);
105 eDebug("");
106 #endif
108 if (ioctl(handle, DMX_SET_FILTER, &secFilterParams) < 0)
110 perror("DMX_SET_FILTER\n");
111 ::close(handle);
112 return -1;
115 #if HAVE_DVB_API_VERSION < 3
116 if ( eSystemInfo::getInstance()->hasNegFilter() )
118 __u8 negfilter[DMX_FILTER_SIZE];
119 memset(negfilter, 0, DMX_FILTER_SIZE);
120 memcpy(negfilter, mode, len);
121 if (::ioctl(handle, DMX_SET_NEGFILTER_MASK, negfilter) < 0)
122 eDebug("DMX_SET_NEGFILTER_MASK (%m)");
123 if (::ioctl(handle, DMX_START, 0) < 0)
124 eDebug("DMX_START failed(%m)");
126 #endif
128 return 0;
131 int eSectionReader::read(__u8 *buf)
133 int rd = ::read(handle, buf, 4098);
134 if (rd < 0)
136 /* backup errno, for instance eDebug could change it */
137 int error = errno;
138 if (error == EAGAIN)
139 return error;
140 eDebug("section read(%m)");
141 return error;
143 if (rd > 0 && (buf[0] & tableid_mask) != (tableid & tableid_mask))
145 eDebug("skip section data.. table_id isn't valid");
146 return -2;
148 #if 0
149 ASSERT(rd <= 4098);
150 if ( rd < 3 )
152 eFatal("read less then 3 bytes from section.. skip");
153 return -1;
155 int seclen=(buf[1]&0x0F)<<8;
156 seclen|=buf[2]&0xFF;
157 seclen+=3;
158 if ( rd < seclen )
160 eFatal("cannot read the complete section(%d/%d)",
161 rd, seclen);
162 return -1;
164 if ( rd > seclen )
166 eFatal("read more bytes than section length(%d/%d)",
167 rd, seclen);
168 return -1;
170 #endif
171 return 0;
174 eSection::eSection(int _pid, int _tableid, int _tableidext, int _version, int _flags, int _tableidmask)
175 :context(eApp), notifier(0), pid(_pid), tableid(_tableid)
176 ,tableidext(_tableidext), tableidmask(_tableidmask), maxsec(0)
177 ,section(-1), flags(_flags), timer(0)
178 ,lockcount(0), version(_version)
180 setContext(context);
183 eSection::eSection()
184 :context(eApp), notifier(0), pid(0), tableid(0), tableidext(0)
185 ,tableidmask(0), maxsec(0), section(-1), flags(0)
186 ,timer(0), lockcount(0), version(0)
188 setContext(context);
191 eSection::~eSection()
193 closeFilter();
194 if (lockcount)
195 eDebug("deleted still locked table");
196 delete timer;
197 timer=0;
200 int eSection::start( const char* dmxdev )
202 if (timer && version==-1)
203 timer->start(
204 pid == 0x14 /* TOT/TDT */ ? 90000 :
205 pid == 0x10 /* NIT */ ? 12000 :
206 pid == 0x00 /* PAT */ ? 4000 :
207 pid == 0x11 /* SDT */ ? 5000 :
208 pid == 0x12 /* EIT */ ? 15000 :
209 tableid == 0x02 /* PMT */ ? 4000 : 10000, true);
210 return setFilter(pid, tableid, tableidext, version, flags, tableidmask, dmxdev);
213 int eSection::setFilter(int pid, int tableid, int tableidext, int version, int flags, int tableidmask, const char *dmxdev)
215 this->pid = pid;
216 this->tableid = tableid,
217 this->tableidext = tableidext;
218 this->version = version;
219 this->flags = flags;
220 this->tableidmask = tableidmask;
221 this->section = -1;
222 this->maxsec = 0;
223 closeFilter();
224 __u8 data[4], mask[4], mode[4];
225 memset(mode,0,4);
226 data[0]=tableid; mask[0]=tableidmask;
227 data[1]=0; mask[1]=0;
228 data[2]=0; mask[2]=0;
229 data[3]=0; mask[3]=0;
230 if (tableidext!=-1)
232 data[1]=tableidext>>8; mask[1]=0xFF;
233 data[2]=tableidext&0xFF; mask[2]=0xFF;
235 if (version!=-1)
237 if ( eSystemInfo::getInstance()->hasNegFilter() )
239 data[3]=version<<1; mask[3]=0x3E; mode[3]=0x3E;
241 else
243 data[3]=version; mask[3]=0xFF;
247 reader.open(pid, data, mask, mode, 4, flags, dmxdev);
248 if (reader.getHandle() < 0)
249 return -ENOENT;
251 if (!(flags&SECREAD_NOABORT))
253 singleLock s(slock);
254 active.push_back(this);
257 if ( timer && (flags&SECREAD_NOTIMEOUT) )
259 delete timer;
260 timer=0;
263 if (notifier)
264 delete notifier;
266 notifier=new eSocketNotifier(context, reader.getHandle(), eSocketNotifier::Read);
268 CONNECT(notifier->activated, eSection::data);
270 return 0;
273 void eSection::closeFilter()
275 if (reader.getHandle()>0)
277 if (!(flags&SECREAD_NOABORT))
279 singleLock s(slock);
280 active.remove(this);
282 delete notifier;
283 notifier=0;
284 if (timer)
285 timer->stop();
286 reader.close();
290 void eSection::data(int socket)
292 (void)socket;
294 while (1)
296 if (lockcount)
297 eDebug("eSection::data on locked section!");
299 int ret = reader.read(buf);
301 switch(ret)
303 case 0:
304 if (section == -1)
306 section=0;
307 if (timer)
308 timer->start(10000, true);
310 break;
311 default:
312 eDebug("section read error %d for pid %04x, tid %02x, tidmask %02x, tidext %04x... restart timeout\n",
313 ret, pid, tableid, tableidmask, tableidext);
314 case EAGAIN:
315 case -2: // internal error table id not correct
316 if (timer)
317 timer->start(10000, true);
318 return;
321 maxsec=buf[7];
323 // printf("%d/%d, we want %d | service_id %04x | version %04x\n", buf[6], maxsec, section, (buf[3]<<8)|buf[4], buf[5]);
325 if (flags&SECREAD_INORDER)
327 if (section != buf[6])
328 break;
329 ++section;
332 version=buf[5];
334 // get new valid data restart timeout
335 int err=sectionRead(buf);
336 if (err)
338 if (err>0)
339 err=0;
340 closeFilter();
341 sectionFinish(err);
342 return;
345 if ( flags&SECREAD_INORDER && section > maxsec )
346 // last section?
348 closeFilter(); // stop feeding
349 sectionFinish(0);
350 break;
353 // when more data to read.. restart timeout..
354 if ( timer )
355 timer->start(10000,true);
359 void eSection::timeout()
361 eDebug("Section timeout PID %04x", pid);
362 closeFilter();
363 sectionFinish(-ETIMEDOUT);
366 int eSection::abort()
368 if (reader.getHandle()>0)
370 closeFilter();
371 sectionFinish(-ECANCELED);
372 return 0;
373 } else
374 return -ENOENT;
377 int eSection::abortAll()
379 singleLock s(slock);
380 for (ePtrList<eSection>::iterator it(active.begin()); it != active.end();)
382 // abort only sections in main context..
383 if ( it->context == eApp )
385 eSection *sec = *it;
386 ++it;
387 sec->abort();
389 else
390 ++it;
392 return 0;
395 int eSection::sectionRead(__u8 *data)
397 (void)data;
398 return -1;
401 void eSection::sectionFinish(int)
405 int eSection::lock()
407 return ++lockcount;
410 int eSection::unlock()
412 if (lockcount)
413 return lockcount--;
414 else
415 eDebug("unlocking... but not locked");
416 return 0;
419 void eSection::setContext( eMainloop *context )
421 this->context = context;
422 delete timer;
423 timer=0;
424 if ( !(flags&SECREAD_NOTIMEOUT) )
426 timer=new eTimer(context);
427 CONNECT(timer->timeout, eSection::timeout);
429 if ( notifier )
430 eWarning("setContext with running notifier !!!");
433 void eTable::sectionFinish(int err)
435 if (err)
436 error=err;
437 ready=1;
438 /*emit*/ tableReady(error);
441 eTable::eTable(int pid, int tableid, int tableidext, int version)
442 :eSection(pid, tableid, tableidext, version
443 ,(pid==0x14)?0:(SECREAD_INORDER|SECREAD_CRC), 0xFF)
444 ,error(0), ready(0)
448 eTable::eTable(int pid, int tableid, int tableidmask, int tableidext, int version)
449 :eSection(pid, tableid, tableidext, version
450 ,(pid==0x14)?0:(SECREAD_INORDER|SECREAD_CRC), tableidmask)
451 ,error(0), ready(0)
455 eTable::eTable()
456 :error(0), ready(0)
460 eTable *eTable::createNext()
462 return 0;
465 void eAUGTable::slotTableReady(int error)
467 getNext(error);