fix dvd hotplug: stop assuming dvd for every other medium. in case of multiple ISO...
[enigma2.git] / lib / dvb / demux.cpp
1 #include <stdio.h>
2 #include <fcntl.h>
3 #include <sys/ioctl.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <signal.h>
7
8 #if HAVE_DVB_API_VERSION < 3
9 #include <ost/dmx.h>
10
11 #ifndef DMX_SET_NEGFILTER_MASK
12         #define DMX_SET_NEGFILTER_MASK   _IOW('o',48,uint8_t *)
13 #endif
14
15 #ifndef DMX_GET_STC
16         struct dmx_stc
17         {
18                 unsigned int num;       /* input : which STC? O..N */
19                 unsigned int base;      /* output: divisor for stc to get 90 kHz clock */
20                 unsigned long long stc; /* output: src in 'base'*90 kHz units */
21         };
22         #define DMX_GET_STC             _IOR('o', 50, struct dmx_stc)
23 #endif
24
25 #else
26 #include <linux/dvb/dmx.h>
27
28 #define HAVE_ADD_PID
29
30 #ifdef HAVE_ADD_PID
31 #define DMX_ADD_PID              _IO('o', 51)
32 #define DMX_REMOVE_PID           _IO('o', 52)
33
34 typedef enum {
35         DMX_TAP_TS = 0,
36         DMX_TAP_PES = DMX_PES_OTHER, /* for backward binary compat. */
37 } dmx_tap_type_t;
38
39 #endif
40
41 #endif
42
43 #include "crc32.h"
44
45 #include <lib/base/eerror.h>
46 #include <lib/base/filepush.h>
47 #include <lib/dvb/idvb.h>
48 #include <lib/dvb/demux.h>
49 #include <lib/dvb/esection.h>
50 #include <lib/dvb/decoder.h>
51 #include <lib/dvb/pvrparse.h>
52
53 eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux)
54 {
55         m_dvr_busy = 0;
56 }
57
58 eDVBDemux::~eDVBDemux()
59 {
60 }
61
62 int eDVBDemux::openDemux(void)
63 {
64         char filename[128];
65 #if HAVE_DVB_API_VERSION < 3
66         snprintf(filename, 128, "/dev/dvb/card%d/demux%d", adapter, demux);
67 #else
68         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", adapter, demux);
69 #endif
70         return ::open(filename, O_RDWR);
71 }
72
73 DEFINE_REF(eDVBDemux)
74
75 RESULT eDVBDemux::setSourceFrontend(int fenum)
76 {
77 #if HAVE_DVB_API_VERSION >= 3
78         int fd = openDemux();
79         int n = DMX_SOURCE_FRONT0 + fenum;
80         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
81         if (res)
82                 eDebug("DMX_SET_SOURCE failed! - %m");
83         else
84                 source = fenum;
85         ::close(fd);
86         return res;
87 #endif
88         return 0;
89 }
90
91 RESULT eDVBDemux::setSourcePVR(int pvrnum)
92 {
93 #if HAVE_DVB_API_VERSION >= 3
94         int fd = openDemux();
95         int n = DMX_SOURCE_DVR0 + pvrnum;
96         int res = ::ioctl(fd, DMX_SET_SOURCE, &n);
97         source = -1;
98         ::close(fd);
99         return res;
100 #endif
101         return 0;
102 }
103
104 RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
105 {
106         RESULT res;
107         reader = new eDVBSectionReader(this, context, res);
108         if (res)
109                 reader = 0;
110         return res;
111 }
112
113 RESULT eDVBDemux::createPESReader(eMainloop *context, ePtr<iDVBPESReader> &reader)
114 {
115         RESULT res;
116         reader = new eDVBPESReader(this, context, res);
117         if (res)
118                 reader = 0;
119         return res;
120 }
121
122 RESULT eDVBDemux::createTSRecorder(ePtr<iDVBTSRecorder> &recorder)
123 {
124         if (m_dvr_busy)
125                 return -EBUSY;
126         recorder = new eDVBTSRecorder(this);
127         return 0;
128 }
129
130 RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder, int primary)
131 {
132         decoder = new eTSMPEGDecoder(this, primary ? 0 : 1);
133         return 0;
134 }
135
136 RESULT eDVBDemux::getSTC(pts_t &pts, int num)
137 {
138         int fd = openDemux();
139         
140         if (fd < 0)
141                 return -ENODEV;
142
143         struct dmx_stc stc;
144         stc.num = num;
145         stc.base = 1;
146         
147         if (ioctl(fd, DMX_GET_STC, &stc) < 0)
148         {
149                 eDebug("DMX_GET_STC failed!");
150                 ::close(fd);
151                 return -1;
152         }
153         
154         pts = stc.stc;
155         
156         eDebug("DMX_GET_STC - %lld", pts);
157         
158         ::close(fd);
159         return 0;
160 }
161
162 RESULT eDVBDemux::flush()
163 {
164         // FIXME: implement flushing the PVR queue here.
165         
166         m_event(evtFlush);
167         return 0;
168 }
169
170 RESULT eDVBDemux::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
171 {
172         conn = new eConnection(this, m_event.connect(event));
173         return 0;
174 }
175
176 void eDVBSectionReader::data(int)
177 {
178         __u8 data[4096]; // max. section size
179         int r;
180         r = ::read(fd, data, 4096);
181         if(r < 0)
182         {
183                 eWarning("ERROR reading section - %m\n");
184                 return;
185         }
186         if (checkcrc)
187         {
188                         // this check should never happen unless the driver is crappy!
189                 unsigned int c;
190                 if ((c = crc32((unsigned)-1, data, r)))
191                 {
192                         eDebug("crc32 failed! is %x\n", c);
193                         return;
194                 }
195         }
196         if (active)
197                 read(data);
198         else
199                 eDebug("data.. but not active");
200 }
201
202 eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): demux(demux)
203 {
204         char filename[128];
205         fd = demux->openDemux();
206         
207         if (fd >= 0)
208         {
209                 notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read, false);
210                 CONNECT(notifier->activated, eDVBSectionReader::data);
211                 res = 0;
212         } else
213         {
214                 perror(filename);
215                 res = errno;
216         }
217 }
218
219 DEFINE_REF(eDVBSectionReader)
220
221 eDVBSectionReader::~eDVBSectionReader()
222 {
223         if (notifier)
224                 delete notifier;
225         if (fd >= 0)
226                 ::close(fd);
227 }
228
229 RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
230 {
231         RESULT res;
232         if (fd < 0)
233                 return -ENODEV;
234
235         notifier->start();
236 #if HAVE_DVB_API_VERSION < 3
237         dmxSctFilterParams sct;
238 #else
239         dmx_sct_filter_params sct;
240 #endif
241         sct.pid     = mask.pid;
242         sct.timeout = 0;
243 #if HAVE_DVB_API_VERSION < 3
244         sct.flags   = 0;
245 #else
246         sct.flags   = DMX_IMMEDIATE_START;
247 #endif
248         if (mask.flags & eDVBSectionFilterMask::rfCRC)
249         {
250                 sct.flags |= DMX_CHECK_CRC;
251                 checkcrc = 1;
252         } else
253                 checkcrc = 0;
254         
255         memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
256         memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
257 #if HAVE_DVB_API_VERSION >= 3
258         memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
259         if (::ioctl(fd, DMX_SET_BUFFER_SIZE, 8192*8) < 0)
260                 eDebug("DMX_SET_BUFFER_SIZE failed(%m)");
261 #endif
262         
263         res = ::ioctl(fd, DMX_SET_FILTER, &sct);
264         if (!res)
265         {
266 #if HAVE_DVB_API_VERSION < 3
267                 res = ::ioctl(fd, DMX_SET_NEGFILTER_MASK, mask.mode);
268                 if (!res)
269                 {
270                         res = ::ioctl(fd, DMX_START, 0);
271                         if (!res)
272                                 active = 1;
273                 }
274 #else
275                 active = 1;
276 #endif
277         }
278         return res;
279 }
280
281 RESULT eDVBSectionReader::stop()
282 {
283         if (!active)
284                 return -1;
285
286         active=0;
287         ::ioctl(fd, DMX_STOP);
288         notifier->stop();
289
290         return 0;
291 }
292
293 RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
294 {
295         conn = new eConnection(this, read.connect(r));
296         return 0;
297 }
298
299 void eDVBPESReader::data(int)
300 {
301         while (1)
302         {
303                 __u8 buffer[16384];
304                 int r;
305                 r = ::read(m_fd, buffer, 16384);
306                 if (!r)
307                         return;
308                 if(r < 0)
309                 {
310                         if (errno == EAGAIN || errno == EINTR) /* ok */
311                                 return;
312                         eWarning("ERROR reading PES (fd=%d) - %m", m_fd);
313                         return;
314                 }
315
316                 if (m_active)
317                         m_read(buffer, r);
318                 else
319                         eWarning("PES reader not active");
320                 if (r != 16384)
321                         break;
322         }
323 }
324
325 eDVBPESReader::eDVBPESReader(eDVBDemux *demux, eMainloop *context, RESULT &res): m_demux(demux)
326 {
327         char filename[128];
328         m_fd = m_demux->openDemux();
329         
330         if (m_fd >= 0)
331         {
332                 ::ioctl(m_fd, DMX_SET_BUFFER_SIZE, 64*1024);
333                 ::fcntl(m_fd, F_SETFL, O_NONBLOCK);
334                 m_notifier = new eSocketNotifier(context, m_fd, eSocketNotifier::Read, false);
335                 CONNECT(m_notifier->activated, eDVBPESReader::data);
336                 res = 0;
337         } else
338         {
339                 perror(filename);
340                 res = errno;
341         }
342 }
343
344 DEFINE_REF(eDVBPESReader)
345
346 eDVBPESReader::~eDVBPESReader()
347 {
348         if (m_notifier)
349                 delete m_notifier;
350         if (m_fd >= 0)
351                 ::close(m_fd);
352 }
353
354 RESULT eDVBPESReader::start(int pid)
355 {
356         RESULT res;
357         if (m_fd < 0)
358                 return -ENODEV;
359
360         m_notifier->start();
361
362 #if HAVE_DVB_API_VERSION < 3
363         dmxPesFilterParams flt;
364         
365         flt.pesType = DMX_PES_OTHER;
366 #else
367         dmx_pes_filter_params flt;
368         
369         flt.pes_type = DMX_PES_OTHER;
370 #endif
371
372         flt.pid     = pid;
373         flt.input   = DMX_IN_FRONTEND;
374         flt.output  = DMX_OUT_TAP;
375         
376         flt.flags   = DMX_IMMEDIATE_START;
377
378         res = ::ioctl(m_fd, DMX_SET_PES_FILTER, &flt);
379         
380         if (res)
381                 eWarning("PES filter: DMX_SET_PES_FILTER - %m");
382         if (!res)
383                 m_active = 1;
384         return res;
385 }
386
387 RESULT eDVBPESReader::stop()
388 {
389         if (!m_active)
390                 return -1;
391
392         m_active=0;
393         ::ioctl(m_fd, DMX_STOP);
394         m_notifier->stop();
395
396         return 0;
397 }
398
399 RESULT eDVBPESReader::connectRead(const Slot2<void,const __u8*,int> &r, ePtr<eConnection> &conn)
400 {
401         conn = new eConnection(this, m_read.connect(r));
402         return 0;
403 }
404
405 class eDVBRecordFileThread: public eFilePushThread
406 {
407 public:
408         eDVBRecordFileThread();
409         void setTimingPID(int pid);
410         
411         void saveTimingInformation(const std::string &filename);
412 protected:
413         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
414 private:
415         eMPEGStreamParserTS m_ts_parser;
416         eMPEGStreamInformation m_stream_info;
417         off_t m_current_offset;
418         int m_pid;
419 };
420
421 eDVBRecordFileThread::eDVBRecordFileThread()
422         :eFilePushThread(IOPRIO_CLASS_RT, 7), m_ts_parser(m_stream_info)
423 {
424         m_current_offset = 0;
425 }
426
427 void eDVBRecordFileThread::setTimingPID(int pid)
428 {
429         m_ts_parser.setPid(pid);
430 }
431
432 void eDVBRecordFileThread::saveTimingInformation(const std::string &filename)
433 {
434         m_stream_info.save(filename.c_str());
435 }
436
437 int eDVBRecordFileThread::filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining)
438 {
439         m_ts_parser.parseData(m_current_offset, data, len);
440         
441         m_current_offset += len;
442         
443         return len;
444 }
445
446 DEFINE_REF(eDVBTSRecorder);
447
448 eDVBTSRecorder::eDVBTSRecorder(eDVBDemux *demux): m_demux(demux)
449 {
450         m_running = 0;
451         m_target_fd = -1;
452         m_thread = new eDVBRecordFileThread();
453   CONNECT(m_thread->m_event, eDVBTSRecorder::filepushEvent);
454 #ifndef HAVE_ADD_PID
455         m_demux->m_dvr_busy = 1;
456 #endif
457 }
458
459 eDVBTSRecorder::~eDVBTSRecorder()
460 {
461         stop();
462         delete m_thread;
463 #ifndef HAVE_ADD_PID
464         m_demux->m_dvr_busy = 0;
465 #endif
466 }
467
468 RESULT eDVBTSRecorder::start()
469 {
470         if (m_running)
471                 return -1;
472         
473         if (m_target_fd == -1)
474                 return -2;
475
476         char filename[128];
477 #ifndef HAVE_ADD_PID
478 #if HAVE_DVB_API_VERSION < 3
479         snprintf(filename, 128, "/dev/dvb/card%d/dvr%d", m_demux->adapter, m_demux->demux);
480 #else
481         snprintf(filename, 128, "/dev/dvb/adapter%d/dvr%d", m_demux->adapter, m_demux->demux);
482 #endif
483         m_source_fd = ::open(filename, O_RDONLY);
484         
485         if (m_source_fd < 0)
486         {
487                 eDebug("FAILED to open dvr (%s) in ts recoder (%m)", filename);
488                 return -3;
489         }
490 #else
491         snprintf(filename, 128, "/dev/dvb/adapter%d/demux%d", m_demux->adapter, m_demux->demux);
492
493         m_source_fd = ::open(filename, O_RDONLY);
494         
495         if (m_source_fd < 0)
496         {
497                 eDebug("FAILED to open demux (%s) in ts recoder (%m)", filename);
498                 return -3;
499         }
500         
501         ::ioctl(m_source_fd, DMX_SET_BUFFER_SIZE, 1024*1024);
502
503         dmx_pes_filter_params flt;
504         flt.pes_type = (dmx_pes_type_t)DMX_TAP_TS;
505         flt.pid     = (__u16)-1;
506         flt.input   = DMX_IN_FRONTEND;
507         flt.output  = DMX_OUT_TAP;
508         flt.flags   = 0;
509         int res = ::ioctl(m_source_fd, DMX_SET_PES_FILTER, &flt);
510         if (res)
511         {
512                 eDebug("DMX_SET_PES_FILTER: %m");
513                 ::close(m_source_fd);
514                 return -3;
515         }
516         
517         ::ioctl(m_source_fd, DMX_START);
518         
519 #endif
520         
521         m_thread->start(m_source_fd, m_target_fd);
522         m_running = 1;
523         
524         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
525                 startPID(i->first);
526         
527         return 0;
528 }
529
530 RESULT eDVBTSRecorder::addPID(int pid)
531 {
532         if (m_pids.find(pid) != m_pids.end())
533                 return -1;
534         
535         m_pids.insert(std::pair<int,int>(pid, -1));
536         if (m_running)
537                 startPID(pid);
538         return 0;
539 }
540
541 RESULT eDVBTSRecorder::removePID(int pid)
542 {
543         if (m_pids.find(pid) == m_pids.end())
544                 return -1;
545                 
546         if (m_running)
547                 stopPID(pid);
548         
549         m_pids.erase(pid);
550         return 0;
551 }
552
553 RESULT eDVBTSRecorder::setTimingPID(int pid)
554 {
555         if (m_running)
556                 return -1;
557         m_thread->setTimingPID(pid);
558         return 0;
559 }
560
561 RESULT eDVBTSRecorder::setTargetFD(int fd)
562 {
563         m_target_fd = fd;
564         return 0;
565 }
566
567 RESULT eDVBTSRecorder::setTargetFilename(const char *filename)
568 {
569         m_target_filename = filename;
570         return 0;
571 }
572
573 RESULT eDVBTSRecorder::setBoundary(off_t max)
574 {
575         return -1; // not yet implemented
576 }
577
578 RESULT eDVBTSRecorder::stop()
579 {
580         for (std::map<int,int>::iterator i(m_pids.begin()); i != m_pids.end(); ++i)
581                 stopPID(i->first);
582
583         if (!m_running)
584                 return -1;
585         m_thread->stop();
586         
587         close(m_source_fd);
588         m_source_fd = -1;
589         
590         if (m_target_filename != "")
591                 m_thread->saveTimingInformation(m_target_filename + ".ap");
592         
593         return 0;
594 }
595
596 RESULT eDVBTSRecorder::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &conn)
597 {
598         conn = new eConnection(this, m_event.connect(event));
599         return 0;
600 }
601
602 RESULT eDVBTSRecorder::startPID(int pid)
603 {
604 #ifndef HAVE_ADD_PID
605         int fd = m_demux->openDemux();
606         if (fd < 0)
607         {
608                 eDebug("FAILED to open demux in ts recoder (%m)");
609                 return -1;
610         }
611
612 #if HAVE_DVB_API_VERSION < 3
613         dmxPesFilterParams flt;
614         
615         flt.pesType = DMX_PES_OTHER;
616 #else
617         dmx_pes_filter_params flt;
618         
619         flt.pes_type = DMX_PES_OTHER;
620 #endif
621
622         flt.pid     = pid;
623         flt.input   = DMX_IN_FRONTEND;
624         flt.output  = DMX_OUT_TS_TAP;
625         
626         flt.flags   = DMX_IMMEDIATE_START;
627
628         int res = ::ioctl(fd, DMX_SET_PES_FILTER, &flt);
629         if (res < 0)
630         {
631                 eDebug("set pes filter failed!");
632                 ::close(fd);
633                 return -1;
634         }
635         m_pids[pid] = fd;
636 #else
637         while(true) {
638                 if (::ioctl(m_source_fd, DMX_ADD_PID, pid) < 0) {
639                         perror("DMX_ADD_PID");
640                         if (errno == EAGAIN || errno == EINTR) {
641                                 eDebug("retry!");
642                                 continue;
643                         }
644                 } else
645                         m_pids[pid] = 1;
646                 break;
647         }
648 #endif
649         return 0;
650 }
651
652 void eDVBTSRecorder::stopPID(int pid)
653 {
654 #ifndef HAVE_ADD_PID
655         if (m_pids[pid] != -1)
656                 ::close(m_pids[pid]);
657 #else
658         if (m_pids[pid] != -1)
659         {
660                 while(true) {
661                         if (::ioctl(m_source_fd, DMX_REMOVE_PID, pid) < 0) {
662                                 perror("DMX_REMOVE_PID");
663                                 if (errno == EAGAIN || errno == EINTR) {
664                                         eDebug("retry!");
665                                         continue;
666                                 }
667                         }
668                         break;
669                 }
670         }
671 #endif
672         m_pids[pid] = -1;
673 }
674
675 void eDVBTSRecorder::filepushEvent(int event)
676 {
677         switch (event)
678         {
679         case eFilePushThread::evtWriteError:
680                 m_event(eventWriteError);
681                 break;
682         }
683 }