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