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