remove old comment, fix returncodes on signal
[enigma2.git] / lib / dvb / dvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/filepush.h>
3 #include <lib/dvb/idvb.h>
4 #include <lib/dvb/dvb.h>
5 #include <lib/dvb/sec.h>
6
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13
14 DEFINE_REF(eDVBRegisteredFrontend);
15 DEFINE_REF(eDVBRegisteredDemux);
16
17 DEFINE_REF(eDVBAllocatedFrontend);
18
19 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
20 {
21         m_fe->m_inuse++;
22 }
23
24 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
25 {
26         --m_fe->m_inuse;
27 }
28
29 DEFINE_REF(eDVBAllocatedDemux);
30
31 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
32 {
33         m_demux->m_inuse++;
34 }
35
36 eDVBAllocatedDemux::~eDVBAllocatedDemux()
37 {
38         --m_demux->m_inuse;
39 }
40
41 DEFINE_REF(eDVBResourceManager);
42
43 eDVBResourceManager *eDVBResourceManager::instance;
44
45 eDVBResourceManager::eDVBResourceManager()
46 {
47         avail = 1;
48         busy = 0;
49         m_sec = new eDVBSatelliteEquipmentControl(m_frontend);
50         if (!instance)
51                 instance = this;
52                 
53                 /* search available adapters... */
54
55                 // add linux devices
56         
57         int num_adapter = 0;
58         while (eDVBAdapterLinux::exist(num_adapter))
59         {
60                 addAdapter(new eDVBAdapterLinux(num_adapter));
61                 num_adapter++;
62         }
63         
64         eDebug("found %d adapter, %d frontends and %d demux", 
65                 m_adapter.size(), m_frontend.size(), m_demux.size());
66 }
67
68
69 DEFINE_REF(eDVBAdapterLinux);
70 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
71 {
72                 // scan frontends
73         int num_fe = 0;
74         
75         eDebug("scanning for frontends..");
76         while (1)
77         {
78                 struct stat s;
79                 char filename[128];
80 #if HAVE_DVB_API_VERSION < 3
81                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
82 #else
83                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
84 #endif
85                 if (stat(filename, &s))
86                         break;
87                 ePtr<eDVBFrontend> fe;
88
89                 int ok = 0;
90                 fe = new eDVBFrontend(m_nr, num_fe, ok);
91                 if (ok)
92                         m_frontend.push_back(fe);
93                 ++num_fe;
94         }
95         
96                 // scan demux
97         int num_demux = 0;
98         while (1)
99         {
100                 struct stat s;
101                 char filename[128];
102 #if HAVE_DVB_API_VERSION < 3
103                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
104 #else
105                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
106 #endif
107                 if (stat(filename, &s))
108                         break;
109                 ePtr<eDVBDemux> demux;
110                 
111                 demux = new eDVBDemux(m_nr, num_demux);
112                 m_demux.push_back(demux);
113                         
114                 ++num_demux;
115         }
116 }
117
118 int eDVBAdapterLinux::getNumDemux()
119 {
120         return m_demux.size();
121 }
122
123 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
124 {
125         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
126         while (nr && (i != m_demux.end()))
127         {
128                 --nr;
129                 ++i;
130         }
131         
132         if (i != m_demux.end())
133                 demux = *i;
134         else
135                 return -1;
136                 
137         return 0;
138 }
139
140 int eDVBAdapterLinux::getNumFrontends()
141 {
142         return m_frontend.size();
143 }
144
145 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
146 {
147         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
148         while (nr && (i != m_frontend.end()))
149         {
150                 --nr;
151                 ++i;
152         }
153         
154         if (i != m_frontend.end())
155                 fe = *i;
156         else
157                 return -1;
158                 
159         return 0;
160 }
161
162 int eDVBAdapterLinux::exist(int nr)
163 {
164         struct stat s;
165         char filename[128];
166 #if HAVE_DVB_API_VERSION < 3
167         sprintf(filename, "/dev/dvb/card%d", nr);
168 #else
169         sprintf(filename, "/dev/dvb/adapter%d", nr);
170 #endif
171         if (!stat(filename, &s))
172                 return 1;
173         return 0;
174 }
175
176 eDVBResourceManager::~eDVBResourceManager()
177 {
178         if (instance == this)
179                 instance = 0;
180 }
181
182 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
183 {
184         int num_fe = adapter->getNumFrontends();
185         int num_demux = adapter->getNumDemux();
186         
187         m_adapter.push_back(adapter);
188         
189         int i;
190         for (i=0; i<num_demux; ++i)
191         {
192                 ePtr<eDVBDemux> demux;
193                 if (!adapter->getDemux(demux, i))
194                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
195         }
196
197         for (i=0; i<num_fe; ++i)
198         {
199                 ePtr<eDVBFrontend> frontend;
200
201                 if (!adapter->getFrontend(frontend, i))
202                 {
203                         frontend->setTone(iDVBFrontend::toneOff);
204                         frontend->setVoltage(iDVBFrontend::voltageOff);
205                         frontend->setSEC(m_sec);
206                         m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
207                 }
208         }
209 }
210
211 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm)
212 {
213         ePtr<eDVBRegisteredFrontend> best;
214         int bestval = 0;
215
216         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
217                 if (!i->m_inuse)
218                 {
219                         int c = i->m_frontend->isCompatibleWith(feparm);
220                         if (c > bestval)
221                         {
222                                 c = bestval;
223                                 best = i;
224                         }
225                 }
226
227         if (best)
228         {
229                 fe = new eDVBAllocatedFrontend(best);
230                 return 0;
231         }
232         
233         fe = 0;
234         
235         return -1;
236 }
237
238 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int nr)
239 {
240         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i, --nr)
241                 if ((!nr) && !i->m_inuse)
242                 {
243                         fe = new eDVBAllocatedFrontend(i);
244                         return 0;
245                 }
246         
247         fe = 0;
248         return -1;
249 }
250
251 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
252 {
253                 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
254                    never use the first one unless we need a decoding demux. */
255
256         eDebug("allocate demux");
257         eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
258         
259         if (i == m_demux.end())
260                 return -1;
261                 
262         int n=0;
263                 /* FIXME: hardware demux policy */
264         if (!(cap & iDVBChannel::capDecode))
265                 ++i, ++n;
266         
267         for (; i != m_demux.end(); ++i, ++n)
268                 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
269                 {
270                         if ((cap & iDVBChannel::capDecode) && n)
271                                 continue;
272                         
273                         demux = new eDVBAllocatedDemux(i);
274                         if (fe)
275                                 demux->get().setSourceFrontend(fe->m_frontend->getID());
276                         else
277                                 demux->get().setSourcePVR(0);
278                         return 0;
279                 }
280         eDebug("demux not found");
281         return -1;
282 }
283
284 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
285 {
286         m_list = list;
287         return 0;
288 }
289
290 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
291 {
292         list = m_list;
293         if (list)
294                 return 0;
295         else
296                 return -ENOENT;
297 }
298
299
300 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
301 {
302                 /* first, check if a channel is already existing. */
303         
304 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
305         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
306         {
307 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
308                 if (i->m_channel_id == channelid)
309                 {
310 //                      eDebug("found shared channel..");
311                         channel = i->m_channel;
312                         return 0;
313                 }
314         }
315         
316         /* no currently available channel is tuned to this channelid. create a new one, if possible. */
317
318         if (!m_list)
319         {
320                 eDebug("no channel list set!");
321                 return -ENOENT;
322         }
323
324         ePtr<iDVBFrontendParameters> feparm;
325         if (m_list->getChannelFrontendData(channelid, feparm))
326         {
327                 eDebug("channel not found!");
328                 return -ENOENT;
329         }
330
331         /* allocate a frontend. */
332         
333         ePtr<eDVBAllocatedFrontend> fe;
334         
335         if (allocateFrontend(fe, feparm))
336                 return errNoFrontend;
337         
338         RESULT res;
339         ePtr<eDVBChannel> ch;
340         ch = new eDVBChannel(this, fe);
341
342         res = ch->setChannel(channelid, feparm);
343         if (res)
344         {
345                 channel = 0;
346                 return errChidNotFound;
347         }
348         
349         channel = ch;
350         return 0;
351 }
352
353 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int frontend_index)
354 {
355         ePtr<eDVBAllocatedFrontend> fe;
356
357         if (allocateFrontendByIndex(fe, frontend_index))
358                 return errNoFrontend;
359         
360         eDVBChannel *ch;
361         ch = new eDVBChannel(this, fe);
362
363         channel = ch;
364         return 0;
365 }
366
367
368 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
369 {
370         ePtr<eDVBAllocatedDemux> demux;
371         
372         eDVBChannel *ch;
373         ch = new eDVBChannel(this, 0);
374         
375         channel = ch;
376         return 0;
377 }
378
379 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
380 {
381         m_active_channels.push_back(active_channel(chid, ch));
382         /* emit */ m_channelAdded(ch);
383         return 0;
384 }
385
386 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
387 {
388         int cnt = 0;
389         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
390         {
391                 if (i->m_channel == ch)
392                 {
393                         i = m_active_channels.erase(i);
394                         ++cnt;
395                 } else
396                         ++i;
397         }
398         ASSERT(cnt == 1);
399         if (cnt == 1)
400                 return 0;
401         return -ENOENT;
402 }
403
404 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
405 {
406         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
407         return 0;
408 }
409
410 DEFINE_REF(eDVBChannel);
411
412 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
413 {
414         m_frontend = frontend;
415
416         m_pvr_thread = 0;
417         
418         if (m_frontend)
419                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
420 }
421
422 eDVBChannel::~eDVBChannel()
423 {
424         if (m_channel_id)
425                 m_mgr->removeChannel(this);
426         
427         if (m_pvr_thread)
428         {
429                 m_pvr_thread->stop();
430                 ::close(m_pvr_fd_src);
431                 ::close(m_pvr_fd_dst);
432                 delete m_pvr_thread;
433         }
434 }
435
436 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
437 {
438         int state, ourstate = 0;
439         
440                 /* if we are already in shutdown, don't change state. */
441         if (m_state == state_release)
442                 return;
443         
444         if (fe->getState(state))
445                 return;
446         
447         if (state == iDVBFrontend::stateLock)
448         {
449                 eDebug("OURSTATE: ok");
450                 ourstate = state_ok;
451         } else if (state == iDVBFrontend::stateTuning)
452         {
453                 eDebug("OURSTATE: tuning");
454                 ourstate = state_tuning;
455         } else if (state == iDVBFrontend::stateLostLock)
456         {
457                 eDebug("OURSTATE: lost lock");
458                 ourstate = state_unavailable;
459         } else if (state == iDVBFrontend::stateFailed)
460         {
461                 eDebug("OURSTATE: failed");
462                 ourstate = state_failed;
463         } else
464                 eFatal("state unknown");
465         
466         if (ourstate != m_state)
467         {
468                 m_state = ourstate;
469                 m_stateChanged(this);
470         }
471 }
472
473 void eDVBChannel::AddUse()
474 {
475         ++m_use_count;
476 }
477
478 void eDVBChannel::ReleaseUse()
479 {
480         if (!--m_use_count)
481         {
482                 m_state = state_release;
483                 m_stateChanged(this);
484         }
485 }
486
487 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
488 {
489         if (m_channel_id)
490                 m_mgr->removeChannel(this);
491                 
492         if (!channelid)
493                 return 0;
494
495         if (!m_frontend)
496         {
497                 eDebug("no frontend to tune!");
498                 return -ENODEV;
499         }
500         
501         m_channel_id = channelid;
502         m_mgr->addChannel(channelid, this);
503         m_state = state_tuning;
504                         /* if tuning fails, shutdown the channel immediately. */
505         int res;
506         res = m_frontend->get().tune(*feparm);
507         
508         if (res)
509         {
510                 m_state = state_release;
511                 m_stateChanged(this);
512                 return res;
513         }
514         
515         return 0;
516 }
517
518 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
519 {
520         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
521         return 0;
522 }
523
524 RESULT eDVBChannel::getState(int &state)
525 {
526         state = m_state;
527         return 0;
528 }
529
530 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
531 {
532         return -1;
533 }
534
535 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
536 {
537         eDebug("get %d demux", cap);
538         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
539         
540         if (!our_demux)
541         {
542                 demux = 0;
543                 
544                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
545                         return -1;
546                 
547         }
548         
549         demux = *our_demux;
550         if (cap & capDecode)
551         {
552                 our_demux = 0;
553         }
554         return 0;
555 }
556
557 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
558 {
559         frontend = &m_frontend->get();
560         if (frontend)
561                 return 0;
562         else
563                 return -ENODEV;
564 }
565
566 RESULT eDVBChannel::playFile(const char *file)
567 {
568         ASSERT(!m_frontend);
569         if (m_pvr_thread)
570         {
571                 m_pvr_thread->stop();
572                 delete m_pvr_thread;
573                 m_pvr_thread = 0;
574         }
575         
576         m_tstools.openFile(file);
577         
578                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
579                    THEN DO A REAL FIX HERE! */
580         
581                 /* (this codepath needs to be improved anyway.) */
582         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
583         if (m_pvr_fd_dst < 0)
584         {
585                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
586                 return -ENODEV;
587         }
588         
589         m_pvr_fd_src = open(file, O_RDONLY);
590         if (m_pvr_fd_src < 0)
591         {
592                 eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
593                 close(m_pvr_fd_dst);
594                 return -ENOENT;
595         }
596         
597         m_state = state_ok;
598         m_stateChanged(this);
599         
600         m_pvr_thread = new eFilePushThread();
601         m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
602
603         return 0;
604 }
605
606 RESULT eDVBChannel::getLength(pts_t &len)
607 {
608         return m_tstools.calcLen(len);
609 }
610
611 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos)
612 {
613         if (!decoding_demux)
614                 return -1;
615         
616         off_t begin = 0;
617                 /* getPTS for offset 0 is cached, so it doesn't harm. */
618         int r = m_tstools.getPTS(begin, pos);
619         if (r)
620         {
621                 eDebug("tstools getpts(0) failed!");
622                 return r;
623         }
624         
625         pts_t now;
626         
627         r = decoding_demux->getSTC(now);
628
629         if (r)
630         {
631                 eDebug("demux getSTC failed");
632                 return -1;
633         }
634         
635 //      eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
636                 /* when we are less than 10 seconds before the start, return 0. */
637                 /* (we're just waiting for the timespam to start) */
638         if ((now < pos) && ((pos - now) < 90000 * 10))
639         {
640                 pos = 0;
641                 return 0;
642         }
643         
644         if (now < pos) /* wrap around */
645                 pos = now + ((pts_t)1)<<33 - pos;
646         else
647                 pos = now - pos;
648         
649         return 0;
650 }
651
652 RESULT eDVBChannel::seekTo(iDVBDemux *decoding_demux, int relative, pts_t &pts)
653 {
654         int bitrate = m_tstools.calcBitrate(); /* in bits/s */
655         
656         if (bitrate == -1)
657                 return -1;
658         
659         if (relative)
660         {
661                 pts_t now;
662                 if (getCurrentPosition(decoding_demux, now))
663                 {
664                         eDebug("seekTo: getCurrentPosition failed!");
665                         return -1;
666                 }
667                 pts += now;
668         }
669         
670         if (pts < 0)
671                 pts = 0;
672         
673         off_t offset = (pts * (pts_t)bitrate) / 8ULL / 90000ULL;
674         
675         seekToPosition(decoding_demux, offset);
676         return 0;
677 }
678
679 RESULT eDVBChannel::seekToPosition(iDVBDemux *decoding_demux, const off_t &r)
680 {
681                         /* when seeking, we have to ensure that all buffers are flushed.
682                            there are basically 3 buffers:
683                            a.) the filepush's internal buffer
684                            b.) the PVR buffer (before demux)
685                            c.) the ratebuffer (after demux)
686                            
687                            it's important to clear them in the correct order, otherwise
688                            the ratebuffer (for example) would immediately refill from
689                            the not-yet-flushed PVR buffer.
690                         */
691         eDebug("eDVBChannel: seekToPosition .. %llx", r);
692         m_pvr_thread->pause();
693
694                 /* flush internal filepush buffer */
695         m_pvr_thread->flush();
696
697                 /* HACK: flush PVR buffer */
698         ::ioctl(m_pvr_fd_dst, 0);
699         
700                 /* flush ratebuffers (video, audio) */
701         if (decoding_demux)
702                 decoding_demux->flush();
703
704                 /* demux will also flush all decoder.. */
705         m_pvr_thread->seek(SEEK_SET, r);
706         m_pvr_thread->resume();
707         return 0;
708 }