factor out genSortName, cleanup comment
[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;
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                 if (!adapter->getFrontend(frontend, i))
201                         m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
202         }
203 }
204
205 RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr<eDVBAllocatedFrontend> &fe)
206 {
207         ePtr<eDVBRegisteredFrontend> best;
208         int bestval = 0;
209         
210         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
211                 if (!i->m_inuse)
212                 {
213                         int c = i->m_frontend->isCompatibleWith(chid);
214                         if (c > bestval)
215                         {
216                                 c = bestval;
217                                 best = i;
218                         }
219                 }
220
221         if (best)
222         {
223                 fe = new eDVBAllocatedFrontend(best);
224                 return 0;
225         }
226         
227         fe = 0;
228         
229         return -1;
230 }
231
232 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
233 {
234                 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
235                    never use the first one unless we need a decoding demux. */
236
237         eDebug("allocate demux");
238         eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
239         
240         if (i == m_demux.end())
241                 return -1;
242                 
243         int n=0;
244                 /* FIXME: hardware demux policy */
245         if (!(cap & iDVBChannel::capDecode))
246                 ++i, ++n;
247         
248         for (; i != m_demux.end(); ++i, ++n)
249                 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
250                 {
251                         if ((cap & iDVBChannel::capDecode) && n)
252                                 continue;
253                         
254                         demux = new eDVBAllocatedDemux(i);
255                         if (fe)
256                                 demux->get().setSourceFrontend(fe->m_frontend->getID());
257                         else
258                                 demux->get().setSourcePVR(0);
259                         return 0;
260                 }
261         eDebug("demux not found");
262         return -1;
263 }
264
265 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
266 {
267         m_list = list;
268         return 0;
269 }
270
271 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
272 {
273         list = m_list;
274         if (list)
275                 return 0;
276         else
277                 return -ENOENT;
278 }
279
280
281 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
282 {
283                 /* first, check if a channel is already existing. */
284         
285 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
286         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
287         {
288 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
289                 if (i->m_channel_id == channelid)
290                 {
291 //                      eDebug("found shared channel..");
292                         channel = i->m_channel;
293                         return 0;
294                 }
295         }
296         
297                 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
298                 
299                 /* allocate a frontend. */
300         
301         ePtr<eDVBAllocatedFrontend> fe;
302         
303         if (allocateFrontend(channelid, fe))
304                 return errNoFrontend;
305         
306 // will be allocated on demand:
307 //      ePtr<eDVBAllocatedDemux> demux;
308 //      
309 //      if (allocateDemux(*fe, demux))
310 //              return errNoDemux;
311         
312         RESULT res;
313         ePtr<eDVBChannel> ch;
314         ch = new eDVBChannel(this, fe);
315
316         ePtr<iDVBFrontend> myfe;
317         if (!ch->getFrontend(myfe))
318                 myfe->setSEC(m_sec);
319
320         res = ch->setChannel(channelid);
321         if (res)
322         {
323                 channel = 0;
324                 return errChidNotFound;
325         }
326         
327         channel = ch;
328         return 0;
329 }
330
331 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
332 {
333         ePtr<eDVBAllocatedFrontend> fe;
334         
335         if (allocateFrontend(eDVBChannelID(), fe))
336                 return errNoFrontend;
337         
338 //      ePtr<eDVBAllocatedDemux> demux;
339         //
340 //      if (allocateDemux(*fe, demux))
341 //              return errNoDemux;
342         
343         eDVBChannel *ch;
344         ch = new eDVBChannel(this, fe);
345
346         ePtr<iDVBFrontend> myfe;
347         if (!ch->getFrontend(myfe))
348                 myfe->setSEC(m_sec);
349
350         channel = ch;
351         return 0;
352 }
353
354
355 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
356 {
357         ePtr<eDVBAllocatedDemux> demux;
358         
359 //      if (allocateDemux(0, demux))
360 //              return errNoDemux;
361         
362         eDVBChannel *ch;
363         ch = new eDVBChannel(this, 0);
364         
365         channel = ch;
366         return 0;
367 }
368
369 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
370 {
371         m_active_channels.push_back(active_channel(chid, ch));
372         /* emit */ m_channelAdded(ch);
373         return 0;
374 }
375
376 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
377 {
378         int cnt = 0;
379         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
380         {
381                 if (i->m_channel == ch)
382                 {
383                         i = m_active_channels.erase(i);
384                         ++cnt;
385                 } else
386                         ++i;
387         }
388         ASSERT(cnt == 1);
389         if (cnt == 1)
390                 return 0;
391         return -ENOENT;
392 }
393
394 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
395 {
396         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
397         return 0;
398 }
399
400 DEFINE_REF(eDVBChannel);
401
402 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
403 {
404         m_frontend = frontend;
405
406         m_pvr_thread = 0;
407         
408         if (m_frontend)
409                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
410 }
411
412 eDVBChannel::~eDVBChannel()
413 {
414         if (m_channel_id)
415                 m_mgr->removeChannel(this);
416         
417         if (m_pvr_thread)
418         {
419                 m_pvr_thread->stop();
420                 ::close(m_pvr_fd_src);
421                 ::close(m_pvr_fd_dst);
422                 delete m_pvr_thread;
423         }
424 }
425
426 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
427 {
428         int state, ourstate = 0;
429         
430                 /* if we are already in shutdown, don't change state. */
431         if (m_state == state_release)
432                 return;
433         
434         if (fe->getState(state))
435                 return;
436         
437         if (state == iDVBFrontend::stateLock)
438         {
439                 eDebug("OURSTATE: ok");
440                 ourstate = state_ok;
441         } else if (state == iDVBFrontend::stateTuning)
442         {
443                 eDebug("OURSTATE: tuning");
444                 ourstate = state_tuning;
445         } else if (state == iDVBFrontend::stateLostLock)
446         {
447                 eDebug("OURSTATE: lost lock");
448                 ourstate = state_unavailable;
449         } else if (state == iDVBFrontend::stateFailed)
450         {
451                 eDebug("OURSTATE: failed");
452                 ourstate = state_failed;
453         } else
454                 eFatal("state unknown");
455         
456         if (ourstate != m_state)
457         {
458                 m_state = ourstate;
459                 m_stateChanged(this);
460         }
461 }
462
463 void eDVBChannel::AddUse()
464 {
465         ++m_use_count;
466 }
467
468 void eDVBChannel::ReleaseUse()
469 {
470         if (!--m_use_count)
471         {
472                 m_state = state_release;
473                 m_stateChanged(this);
474         }
475 }
476
477 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
478 {
479         if (m_channel_id)
480                 m_mgr->removeChannel(this);
481                 
482         if (!channelid)
483                 return 0;
484
485         ePtr<iDVBChannelList> list;
486         
487         if (m_mgr->getChannelList(list))
488         {
489                 eDebug("no channel list set!");
490                 return -ENOENT;
491         }
492         
493         eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
494                 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
495
496         ePtr<iDVBFrontendParameters> feparm;
497         if (list->getChannelFrontendData(channelid, feparm))
498         {
499                 eDebug("channel not found!");
500                 return -ENOENT;
501         }
502         
503         if (!m_frontend)
504         {
505                 eDebug("no frontend to tune!");
506                 return -ENODEV;
507         }
508         
509         m_channel_id = channelid;
510         m_mgr->addChannel(channelid, this);
511         m_state = state_tuning;
512                         /* if tuning fails, shutdown the channel immediately. */
513         int res;
514         res = m_frontend->get().tune(*feparm);
515         
516         if (res)
517         {
518                 m_state = state_release;
519                 m_stateChanged(this);
520                 return res;
521         }
522         
523         return 0;
524 }
525
526 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
527 {
528         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
529         return 0;
530 }
531
532 RESULT eDVBChannel::getState(int &state)
533 {
534         state = m_state;
535         return 0;
536 }
537
538 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
539 {
540         return -1;
541 }
542
543 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
544 {
545         eDebug("get %d demux", cap);
546         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
547         
548         if (!our_demux)
549         {
550                 demux = 0;
551                 
552                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
553                         return -1;
554                 
555         }
556         
557         demux = *our_demux;
558         if (cap & capDecode)
559         {
560                 our_demux = 0;
561         }
562         return 0;
563 }
564
565 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
566 {
567         frontend = &m_frontend->get();
568         if (frontend)
569                 return 0;
570         else
571                 return -ENODEV;
572 }
573
574 RESULT eDVBChannel::playFile(const char *file)
575 {
576         ASSERT(!m_frontend);
577         if (m_pvr_thread)
578         {
579                 m_pvr_thread->stop();
580                 delete m_pvr_thread;
581                 m_pvr_thread = 0;
582         }
583         
584         m_tstools.openFile(file);
585         
586                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
587                    THEN DO A REAL FIX HERE! */
588         
589                 /* (this codepath needs to be improved anyway.) */
590         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
591         if (m_pvr_fd_dst < 0)
592         {
593                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)");
594                 return -ENODEV;
595         }
596         
597         m_pvr_fd_src = open(file, O_RDONLY);
598         if (m_pvr_fd_src < 0)
599         {
600                 eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
601                 close(m_pvr_fd_dst);
602                 return -ENOENT;
603         }
604         
605         m_state = state_ok;
606         m_stateChanged(this);
607         
608         m_pvr_thread = new eFilePushThread();
609         m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
610
611         return 0;
612 }
613
614 RESULT eDVBChannel::getLength(pts_t &len)
615 {
616         return m_tstools.calcLen(len);
617 }
618
619 RESULT eDVBChannel::getCurrentPosition(pts_t &pos)
620 {
621         if (!m_decoder_demux)
622                 return -1;
623         
624         off_t begin = 0;
625                 /* getPTS for offset 0 is cached, so it doesn't harm. */
626         int r = m_tstools.getPTS(begin, pos);
627         if (r)
628         {
629                 eDebug("tstools getpts(0) failed!");
630                 return r;
631         }
632         
633         pts_t now;
634         
635         r = m_decoder_demux->get().getSTC(now);
636
637         if (r)
638         {
639                 eDebug("demux getSTC failed");
640                 return -1;
641         }
642         
643 //      eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
644                 /* when we are less than 10 seconds before the start, return 0. */
645                 /* (we're just waiting for the timespam to start) */
646         if ((now < pos) && ((pos - now) < 90000 * 10))
647         {
648                 pos = 0;
649                 return 0;
650         }
651         
652         if (now < pos) /* wrap around */
653                 pos = now + ((pts_t)1)<<33 - pos;
654         else
655                 pos = now - pos;
656         
657         return 0;
658 }
659
660 RESULT eDVBChannel::seekTo(int relative, pts_t &pts)
661 {
662         int bitrate = m_tstools.calcBitrate(); /* in bits/s */
663         
664         if (bitrate == -1)
665                 return -1;
666         
667         if (relative)
668         {
669                 pts_t now;
670                 if (getCurrentPosition(now))
671                 {
672                         eDebug("seekTo: getCurrentPosition failed!");
673                         return -1;
674                 }
675                 pts += now;
676         }
677         
678         if (pts < 0)
679                 pts = 0;
680         
681         off_t offset = (pts * (pts_t)bitrate) / 8ULL / 90000ULL;
682         
683         seekToPosition(offset);
684         return 0;
685 }
686
687 RESULT eDVBChannel::seekToPosition(const off_t &r)
688 {
689                         /* when seeking, we have to ensure that all buffers are flushed.
690                            there are basically 3 buffers:
691                            a.) the filepush's internal buffer
692                            b.) the PVR buffer (before demux)
693                            c.) the ratebuffer (after demux)
694                            
695                            it's important to clear them in the correct order, otherwise
696                            the ratebuffer (for example) would immediately refill from
697                            the not-yet-flushed PVR buffer.
698                         */
699         eDebug("eDVBChannel: seekToPosition .. %llx", r);
700         m_pvr_thread->pause();
701
702                 /* flush internal filepush buffer */
703         m_pvr_thread->flush();
704
705                 /* HACK: flush PVR buffer */
706         ::ioctl(m_pvr_fd_dst, 0);
707         
708                 /* flush ratebuffers (video, audio) */
709         if (m_decoder_demux)
710                 m_decoder_demux->get().flush();
711
712                 /* demux will also flush all decoder.. */
713         m_pvr_thread->seek(SEEK_SET, r);
714         m_pvr_thread->resume();
715         return 0;
716 }