- add dvb resource management
[enigma2.git] / lib / dvb / demux.cpp
1 #include <config.h>
2 #include <stdio.h>
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 #include <errno.h>
6 #include <unistd.h>
7
8 #if HAVE_DVB_API_VERSION < 3
9 #include <ost/dmx.h>
10 #ifndef DMX_SET_NEGFILTER_MASK
11         #define DMX_SET_NEGFILTER_MASK   _IOW('o',48,uint8_t *)
12 #endif
13 #else
14 #include <linux/dvb/dmx.h>
15 #endif
16
17 #include "crc32.h"
18
19 #include <lib/base/eerror.h>
20 #include <lib/dvb/idvb.h>
21 #include <lib/dvb/demux.h>
22 #include <lib/dvb/esection.h>
23 #include <lib/dvb/decoder.h>
24
25 eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux)
26 {
27 }
28
29 eDVBDemux::~eDVBDemux()
30 {
31 }
32
33 DEFINE_REF(eDVBDemux)
34
35 RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
36 {
37         RESULT res;
38         reader = new eDVBSectionReader(this, context, res);
39         if (res)
40                 reader = 0;
41         return res;
42 }
43
44 RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder)
45 {
46         decoder = new eTSMPEGDecoder(this, 0);
47         return 0;
48 }
49
50 void eDVBSectionReader::data(int)
51 {
52         __u8 data[4096]; // max. section size
53         int r;
54         r = ::read(fd, data, 4096);
55         if(r < 0)
56         {
57                 eWarning("ERROR reading section - %m\n");
58                 return;
59         }
60         if (checkcrc)
61         {
62                         // this check should never happen unless the driver is crappy!
63                 unsigned int c;
64                 if ((c = crc32((unsigned)-1, data, r)))
65                         eFatal("crc32 failed! is %x\n", c);
66         }
67         read(data);
68 }
69
70 eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux)
71 {
72         char filename[128];
73 #if HAVE_DVB_API_VERSION < 3
74         sprintf(filename, "/dev/dvb/card%d/demux%d", demux->adapter, demux->demux);
75 #else
76         sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
77 #endif
78         fd = ::open(filename, O_RDWR);
79         
80         eDebug("eDVBSectionReader has fd %d", fd);
81         
82         if (fd >= 0)
83         {
84                 notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read);
85                 CONNECT(notifier->activated, eDVBSectionReader::data);
86                 res = 0;
87         } else
88         {
89                 perror(filename);
90                 res = errno;
91         }
92 }
93
94 DEFINE_REF(eDVBSectionReader)
95
96 eDVBSectionReader::~eDVBSectionReader()
97 {
98         if (notifier)
99                 delete notifier;
100         if (fd >= 0)
101                 ::close(fd);
102 }
103
104 RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
105 {
106         RESULT res;
107         if (fd < 0)
108                 return -ENODEV;
109
110 #if HAVE_DVB_API_VERSION < 3
111         dmxSctFilterParams sct;
112 #else
113         dmx_sct_filter_params sct;
114 #endif
115         sct.pid     = mask.pid;
116         sct.timeout = 0;
117 #if HAVE_DVB_API_VERSION < 3
118         sct.flags   = 0;
119 #else
120         sct.flags   = DMX_IMMEDIATE_START;
121 #endif
122         if (mask.flags & eDVBSectionFilterMask::rfCRC)
123         {
124                 sct.flags |= DMX_CHECK_CRC;
125                 checkcrc = 1;
126         } else
127                 checkcrc = 0;
128         
129         memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
130         memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
131 #if HAVE_DVB_API_VERSION >= 3
132         memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
133 #endif
134         
135         res = ::ioctl(fd, DMX_SET_FILTER, &sct);
136         if (!res)
137         {
138 #if HAVE_DVB_API_VERSION < 3
139                 res = ::ioctl(fd, DMX_SET_NEGFILTER_MASK, mask.mode);
140                 if (!res)
141                 {
142                         res = ::ioctl(fd, DMX_START, 0);
143                         if (!res)
144                                 active = 1;
145                 }
146 #else
147                 active = 1;
148 #endif
149         }
150         return res;
151 }
152
153 RESULT eDVBSectionReader::stop()
154 {
155         if (!active)
156                 return -1;
157         
158         ::ioctl(fd, DMX_STOP);
159         
160         return 0;
161 }
162
163 RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
164 {
165         conn = new eConnection(this, read.connect(r));
166         return 0;
167 }