copy lists, not list identities... should fix saving of non-default values
[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 #include <signal.h>
8
9 #if HAVE_DVB_API_VERSION < 3
10 #include <ost/dmx.h>
11
12 #ifndef DMX_SET_NEGFILTER_MASK
13         #define DMX_SET_NEGFILTER_MASK   _IOW('o',48,uint8_t *)
14 #endif
15
16 #ifndef DMX_GET_STC
17         struct dmx_stc
18         {
19                 unsigned int num;       /* input : which STC? O..N */
20                 unsigned int base;      /* output: divisor for stc to get 90 kHz clock */
21                 unsigned long long stc; /* output: src in 'base'*90 kHz units */
22         };
23         #define DMX_GET_STC             _IOR('o', 50, struct dmx_stc)
24 #endif
25
26 #else
27 #include <linux/dvb/dmx.h>
28 #endif
29
30 #include "crc32.h"
31
32 #include <lib/base/eerror.h>
33 #include <lib/base/filepush.h>
34 #include <lib/dvb/idvb.h>
35 #include <lib/dvb/demux.h>
36 #include <lib/dvb/esection.h>
37 #include <lib/dvb/decoder.h>
38
39 eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux)
40 {
41         m_dvr_busy = 0;
42 }
43
44 eDVBDemux::~eDVBDemux()
45 {
46 }
47
48 int eDVBDemux::openDemux(void)
49 {
50         char filename[128];
51 #if HAVE_DVB_API_VERSION < 3
52         snprintf(filename, 128, "/dev/dvb/card%d/demux%d", adapter, demux);
53 #else
54         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", adapter, demux);
55 #endif
56         return ::open(filename, O_RDWR);
57 }
58
59 DEFINE_REF(eDVBDemux)
60
61 RESULT eDVBDemux::setSourceFrontend(int fenum)
62 {
63 #if HAVE_DVB_API_VERSION >= 3
64         int fd = openDemux();
65         
66         int n = DMX_SOURCE_FRONT0 + fenum;
67         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
68         if (res)
69                 eDebug("DMX_SET_SOURCE failed! - %m");
70         ::close(fd);
71         return res;
72 #endif
73         return 0;
74 }
75
76 RESULT eDVBDemux::setSourcePVR(int pvrnum)
77 {
78 #if HAVE_DVB_API_VERSION >= 3
79         int fd = openDemux();
80         int n = DMX_SOURCE_DVR0 + pvrnum;
81         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
82         ::close(fd);
83         return res;
84 #endif
85         return 0;
86 }
87
88 RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
89 {
90         RESULT res;
91         reader = new eDVBSectionReader(this, context, res);
92         if (res)
93                 reader = 0;
94         return res;
95 }
96
97 RESULT eDVBDemux::createTSRecorder(ePtr<iDVBTSRecorder> &recorder)
98 {
99         if (m_dvr_busy)
100                 return -EBUSY;
101         recorder = new eDVBTSRecorder(this);
102         return 0;
103 }
104
105 RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder)
106 {
107         decoder = new eTSMPEGDecoder(this, 0);
108         return 0;
109 }
110
111 RESULT eDVBDemux::getSTC(pts_t &pts, int num)
112 {
113         int fd = openDemux();
114         
115         if (fd < 0)
116                 return -ENODEV;
117
118         struct dmx_stc stc;
119         stc.num = num;
120         stc.base = 1;
121         
122         if (ioctl(fd, DMX_GET_STC, &stc) < 0)
123         {
124                 ::close(fd);
125                 return -1;
126         }
127         
128         pts = stc.stc;
129         
130         ::close(fd);
131         return 0;
132 }
133
134 RESULT eDVBDemux::flush()
135 {
136         // FIXME: implement flushing the PVR queue here.
137         
138         m_event(evtFlush);
139         return 0;
140 }
141
142 RESULT eDVBDemux::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
143 {
144         conn = new eConnection(this, m_event.connect(event));
145         return 0;
146 }
147
148 void eDVBSectionReader::data(int)
149 {
150         __u8 data[4096]; // max. section size
151         int r;
152         r = ::read(fd, data, 4096);
153         if(r < 0)
154         {
155                 eWarning("ERROR reading section - %m\n");
156                 return;
157         }
158         if (checkcrc)
159         {
160                         // this check should never happen unless the driver is crappy!
161                 unsigned int c;
162                 if ((c = crc32((unsigned)-1, data, r)))
163                 {
164                         eDebug("crc32 failed! is %x\n", c);
165                         return;
166                 }
167         }
168         if (active)
169                 read(data);
170         else
171                 eDebug("data.. but not active");
172 }
173
174 eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux)
175 {
176         char filename[128];
177         fd = demux->openDemux();
178         
179         if (fd >= 0)
180         {
181                 notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read, false);
182                 CONNECT(notifier->activated, eDVBSectionReader::data);
183                 res = 0;
184         } else
185         {
186                 perror(filename);
187                 res = errno;
188         }
189 }
190
191 DEFINE_REF(eDVBSectionReader)
192
193 eDVBSectionReader::~eDVBSectionReader()
194 {
195         if (notifier)
196                 delete notifier;
197         if (fd >= 0)
198                 ::close(fd);
199 }
200
201 RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
202 {
203         RESULT res;
204         if (fd < 0)
205                 return -ENODEV;
206
207         notifier->start();
208 #if HAVE_DVB_API_VERSION < 3
209         dmxSctFilterParams sct;
210 #else
211         dmx_sct_filter_params sct;
212 #endif
213         sct.pid     = mask.pid;
214         sct.timeout = 0;
215 #if HAVE_DVB_API_VERSION < 3
216         sct.flags   = 0;
217 #else
218         sct.flags   = DMX_IMMEDIATE_START;
219 #endif
220         if (mask.flags & eDVBSectionFilterMask::rfCRC)
221         {
222                 sct.flags |= DMX_CHECK_CRC;
223                 checkcrc = 1;
224         } else
225                 checkcrc = 0;
226         
227         memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
228         memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
229 #if HAVE_DVB_API_VERSION >= 3
230         memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
231         if (::ioctl(fd, DMX_SET_BUFFER_SIZE, 8192*8) < 0)
232                 eDebug("DMX_SET_BUFFER_SIZE failed(%m)");
233 #endif
234         
235         res = ::ioctl(fd, DMX_SET_FILTER, &sct);
236         if (!res)
237         {
238 #if HAVE_DVB_API_VERSION < 3
239                 res = ::ioctl(fd, DMX_SET_NEGFILTER_MASK, mask.mode);
240                 if (!res)
241                 {
242                         res = ::ioctl(fd, DMX_START, 0);
243                         if (!res)
244                                 active = 1;
245                 }
246 #else
247                 active = 1;
248 #endif
249         }
250         return res;
251 }
252
253 RESULT eDVBSectionReader::stop()
254 {
255         if (!active)
256                 return -1;
257
258         active=0;
259         ::ioctl(fd, DMX_STOP);
260         notifier->stop();
261
262         return 0;
263 }
264
265 RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
266 {
267         conn = new eConnection(this, read.connect(r));
268         return 0;
269 }
270
271 DEFINE_REF(eDVBTSRecorder);
272
273 eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux)
274 {
275         m_running = 0;
276         m_format = 0;
277         m_target_fd = -1;
278         m_thread = new eFilePushThread();
279         m_demux->m_dvr_busy = 1;
280 }
281
282 eDVBTSRecorder::~eDVBTSRecorder()
283 {
284         stop();
285         delete m_thread;
286         m_demux->m_dvr_busy = 0;
287 }
288
289 RESULT eDVBTSRecorder::start()
290 {
291         if (m_running)
292                 return -1;
293         
294         if (m_target_fd == -1)
295                 return -2;
296                 
297         char filename[128];
298 #if HAVE_DVB_API_VERSION < 3
299         snprintf(filename, 128, "/dev/dvb/card%d/dvr%d", m_demux->adapter, m_demux->demux);
300 #else
301         snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", m_demux->adapter, m_demux->demux);
302 #endif
303         m_source_fd = ::open(filename, O_RDONLY);
304         
305         if (m_source_fd < 0)
306         {
307                 eDebug("FAILED to open dvr (%s) in ts recoder (%m)", filename);
308                 return -3;
309         }
310         
311         m_thread->start(m_source_fd, m_target_fd);
312         m_running = 1;
313         
314         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
315                 startPID(i->first);
316         
317         return 0;
318 }
319
320 RESULT eDVBTSRecorder::addPID(int pid)
321 {
322         if (m_pids.find(pid) != m_pids.end())
323                 return -1;
324         
325         m_pids.insert(std::pair<int,int>(pid, -1));
326         if (m_running)
327                 startPID(pid);
328         return 0;
329 }
330
331 RESULT eDVBTSRecorder::removePID(int pid)
332 {
333         if (m_pids.find(pid) == m_pids.end())
334                 return -1;
335                 
336         if (m_running)
337                 stopPID(pid);
338         
339         m_pids.erase(pid);
340         return 0;
341 }
342
343 RESULT eDVBTSRecorder::setFormat(int format)
344 {
345         if (m_running)
346                 return -1;
347         m_format = format;
348         return 0;
349 }
350
351 RESULT eDVBTSRecorder::setTargetFD(int fd)
352 {
353         m_target_fd = fd;
354         return 0;
355 }
356
357 RESULT eDVBTSRecorder::setBoundary(off_t max)
358 {
359         return -1; // not yet implemented
360 }
361
362 RESULT eDVBTSRecorder::stop()
363 {
364         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
365                 stopPID(i->first);
366
367         if (!m_running)
368                 return -1;
369         m_thread->stop();
370         
371         close(m_source_fd);
372         
373         return 0;
374 }
375
376 RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
377 {
378         conn = new eConnection(this, m_event.connect(event));
379         return 0;
380 }
381
382 RESULT eDVBTSRecorder::startPID(int pid)
383 {
384         int fd = m_demux->openDemux();
385         if (fd < 0)
386         {
387                 eDebug("FAILED to open demux in ts recoder (%m)");
388                 return -1;
389         }
390
391 #if HAVE_DVB_API_VERSION < 3
392         dmxPesFilterParams flt;
393         
394         flt.pesType = DMX_PES_OTHER;
395 #else
396         dmx_pes_filter_params flt;
397         
398         flt.pes_type = DMX_PES_OTHER;
399 #endif
400
401         flt.pid     = pid;
402         flt.input   = DMX_IN_FRONTEND;
403         flt.output  = DMX_OUT_TS_TAP;
404         
405         flt.flags   = DMX_IMMEDIATE_START;
406
407         int res = ::ioctl(fd, DMX_SET_PES_FILTER, &flt);
408         if (res < 0)
409         {
410                 eDebug("set pes filter failed!");
411                 ::close(fd);
412                 return -1;
413         }
414         m_pids[pid] = fd;
415
416         return 0;
417 }
418
419 void eDVBTSRecorder::stopPID(int pid)
420 {
421         if (m_pids[pid] != -1)
422                 ::close(m_pids[pid]);
423         m_pids[pid] = -1;
424 }