add demux handling (for decoder and record)
[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
13 DEFINE_REF(eDVBRegisteredFrontend);
14 DEFINE_REF(eDVBRegisteredDemux);
15
16 DEFINE_REF(eDVBAllocatedFrontend);
17
18 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
19 {
20         m_fe->m_inuse++;
21 }
22
23 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
24 {
25         --m_fe->m_inuse;
26 }
27
28 DEFINE_REF(eDVBAllocatedDemux);
29
30 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
31 {
32         m_demux->m_inuse++;
33 }
34
35 eDVBAllocatedDemux::~eDVBAllocatedDemux()
36 {
37         --m_demux->m_inuse;
38 }
39
40 DEFINE_REF(eDVBResourceManager);
41
42 eDVBResourceManager *eDVBResourceManager::instance;
43
44 eDVBResourceManager::eDVBResourceManager()
45 {
46         avail = 1;
47         busy = 0;
48         m_sec = new eDVBSatelliteEquipmentControl;
49         if (!instance)
50                 instance = this;
51                 
52                 /* search available adapters... */
53
54                 // add linux devices
55         
56         int num_adapter = 0;
57         while (eDVBAdapterLinux::exist(num_adapter))
58         {
59                 addAdapter(new eDVBAdapterLinux(num_adapter));
60                 num_adapter++;
61         }
62         
63         eDebug("found %d adapter, %d frontends and %d demux", 
64                 m_adapter.size(), m_frontend.size(), m_demux.size());
65 }
66
67
68 DEFINE_REF(eDVBAdapterLinux);
69 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
70 {
71                 // scan frontends
72         int num_fe = 0;
73         
74         eDebug("scanning for frontends..");
75         while (1)
76         {
77                 struct stat s;
78                 char filename[128];
79 #if HAVE_DVB_API_VERSION < 3
80                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
81 #else
82                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
83 #endif
84                 if (stat(filename, &s))
85                         break;
86                 ePtr<eDVBFrontend> fe;
87
88                 int ok = 0;
89                 fe = new eDVBFrontend(m_nr, num_fe, ok);
90                 if (ok)
91                         m_frontend.push_back(fe);
92                 ++num_fe;
93         }
94         
95                 // scan demux
96         int num_demux = 0;
97         while (1)
98         {
99                 struct stat s;
100                 char filename[128];
101 #if HAVE_DVB_API_VERSION < 3
102                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
103 #else
104                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
105 #endif
106                 if (stat(filename, &s))
107                         break;
108                 ePtr<eDVBDemux> demux;
109                 
110                 demux = new eDVBDemux(m_nr, num_demux);
111                 m_demux.push_back(demux);
112                         
113                 ++num_demux;
114         }
115 }
116
117 int eDVBAdapterLinux::getNumDemux()
118 {
119         return m_demux.size();
120 }
121
122 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
123 {
124         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
125         while (nr && (i != m_demux.end()))
126         {
127                 --nr;
128                 ++i;
129         }
130         
131         if (i != m_demux.end())
132                 demux = *i;
133         else
134                 return -1;
135                 
136         return 0;
137 }
138
139 int eDVBAdapterLinux::getNumFrontends()
140 {
141         return m_frontend.size();
142 }
143
144 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
145 {
146         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
147         while (nr && (i != m_frontend.end()))
148         {
149                 --nr;
150                 ++i;
151         }
152         
153         if (i != m_frontend.end())
154                 fe = *i;
155         else
156                 return -1;
157                 
158         return 0;
159 }
160
161 int eDVBAdapterLinux::exist(int nr)
162 {
163         struct stat s;
164         char filename[128];
165 #if HAVE_DVB_API_VERSION < 3
166         sprintf(filename, "/dev/dvb/card%d", nr);
167 #else
168         sprintf(filename, "/dev/dvb/adapter%d", nr);
169 #endif
170         if (!stat(filename, &s))
171                 return 1;
172         return 0;
173 }
174
175 eDVBResourceManager::~eDVBResourceManager()
176 {
177         if (instance == this)
178                 instance = 0;
179
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                 /* FIXME: hardware demux policy */
229         if (!(cap & iDVBChannel::capDecode))
230                 ++i;
231         
232         for (; i != m_demux.end(); ++i)
233                 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
234                 {
235                         demux = new eDVBAllocatedDemux(i);
236                         eDebug("demux found");
237                         return 0;
238                 }
239         eDebug("demux not found");
240         return -1;
241 }
242
243 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
244 {
245         m_list = list;
246         return 0;
247 }
248
249 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
250 {
251         list = m_list;
252         if (list)
253                 return 0;
254         else
255                 return -ENOENT;
256 }
257
258
259 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
260 {
261                 /* first, check if a channel is already existing. */
262         
263 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
264         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
265         {
266 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
267                 if (i->m_channel_id == channelid)
268                 {
269 //                      eDebug("found shared channel..");
270                         channel = i->m_channel;
271                         return 0;
272                 }
273         }
274         
275                 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
276                 
277                 /* allocate a frontend. */
278         
279         ePtr<eDVBAllocatedFrontend> fe;
280         
281         if (allocateFrontend(channelid, fe))
282                 return errNoFrontend;
283         
284 // will be allocated on demand:
285 //      ePtr<eDVBAllocatedDemux> demux;
286 //      
287 //      if (allocateDemux(*fe, demux))
288 //              return errNoDemux;
289         
290         RESULT res;
291         eDVBChannel *ch;
292         ch = new eDVBChannel(this, fe);
293
294         ePtr<iDVBFrontend> myfe;
295         if (!ch->getFrontend(myfe))
296                 myfe->setSEC(m_sec);
297
298         res = ch->setChannel(channelid);
299         if (res)
300         {
301                 channel = 0;
302                 return errChidNotFound;
303         }
304         
305         channel = ch;
306         return 0;
307 }
308
309 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
310 {
311         ePtr<eDVBAllocatedFrontend> fe;
312         
313         if (allocateFrontend(eDVBChannelID(), fe))
314                 return errNoFrontend;
315         
316 //      ePtr<eDVBAllocatedDemux> demux;
317         //
318 //      if (allocateDemux(*fe, demux))
319 //              return errNoDemux;
320         
321         eDVBChannel *ch;
322         ch = new eDVBChannel(this, fe);
323
324         ePtr<iDVBFrontend> myfe;
325         if (!ch->getFrontend(myfe))
326                 myfe->setSEC(m_sec);
327
328         channel = ch;
329         return 0;
330 }
331
332
333 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
334 {
335         ePtr<eDVBAllocatedDemux> demux;
336         
337 //      if (allocateDemux(0, demux))
338 //              return errNoDemux;
339         
340         eDVBChannel *ch;
341         ch = new eDVBChannel(this, 0);
342         
343         channel = ch;
344         return 0;
345 }
346
347 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
348 {
349         eDebug("add channel %p", ch);
350         m_active_channels.push_back(active_channel(chid, ch));
351         /* emit */ m_channelAdded(ch);
352         return 0;
353 }
354
355 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
356 {
357         int cnt = 0;
358         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
359         {
360                 if (i->m_channel == ch)
361                 {
362                         i = m_active_channels.erase(i);
363                         ++cnt;
364                 } else
365                         ++i;
366         }
367         ASSERT(cnt == 1);
368         if (cnt == 1)
369                 return 0;
370         return -ENOENT;
371 }
372
373 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
374 {
375         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
376         return 0;
377 }
378
379 DEFINE_REF(eDVBChannel);
380
381 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
382 {
383         m_frontend = frontend;
384
385         m_pvr_thread = 0;
386         
387         if (m_frontend)
388                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
389 }
390
391 eDVBChannel::~eDVBChannel()
392 {
393         if (m_channel_id)
394                 m_mgr->removeChannel(this);
395         
396         if (m_pvr_thread)
397         {
398                 m_pvr_thread->stop();
399                 ::close(m_pvr_fd_src);
400                 ::close(m_pvr_fd_dst);
401                 delete m_pvr_thread;
402         }
403 }
404
405 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
406 {
407         eDebug("fe state changed!");
408         int state, ourstate = 0;
409         
410                 /* if we are already in shutdown, don't change state. */
411         if (m_state == state_release)
412                 return;
413         
414         if (fe->getState(state))
415                 return;
416         
417         if (state == iDVBFrontend::stateLock)
418         {
419                 eDebug("OURSTATE: ok");
420                 ourstate = state_ok;
421         } else if (state == iDVBFrontend::stateTuning)
422         {
423                 eDebug("OURSTATE: tuning");
424                 ourstate = state_tuning;
425         } else if (state == iDVBFrontend::stateFailed)
426         {
427                 eDebug("OURSTATE: failed/unavailable");
428                 ourstate = state_unavailable;
429         } else
430                 eFatal("state unknown");
431         
432         if (ourstate != m_state)
433         {
434                 m_state = ourstate;
435                 m_stateChanged(this);
436         }
437 }
438
439 void eDVBChannel::AddUse()
440 {
441         ++m_use_count;
442 }
443
444 void eDVBChannel::ReleaseUse()
445 {
446         if (!--m_use_count)
447         {
448                 m_state = state_release;
449                 m_stateChanged(this);
450         }
451 }
452
453 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
454 {
455         if (m_channel_id)
456                 m_mgr->removeChannel(this);
457                 
458         if (!channelid)
459                 return 0;
460
461         ePtr<iDVBChannelList> list;
462         
463         if (m_mgr->getChannelList(list))
464         {
465                 eDebug("no channel list set!");
466                 return -ENOENT;
467         }
468         
469         eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
470                 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
471
472         ePtr<iDVBFrontendParameters> feparm;
473         if (list->getChannelFrontendData(channelid, feparm))
474         {
475                 eDebug("channel not found!");
476                 return -ENOENT;
477         }
478         eDebug("allocateChannel: channel found..");
479         
480         if (!m_frontend)
481         {
482                 eDebug("no frontend to tune!");
483                 return -ENODEV;
484         }
485         
486         m_channel_id = channelid;
487         m_mgr->addChannel(channelid, this);
488         m_state = state_tuning;
489         return m_frontend->get().tune(*feparm);
490 }
491
492 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
493 {
494         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
495         return 0;
496 }
497
498 RESULT eDVBChannel::getState(int &state)
499 {
500         state = m_state;
501         return 0;
502 }
503
504 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
505 {
506         return -1;
507 }
508
509 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
510 {
511         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
512         
513         if (!our_demux)
514         {
515                 demux = 0;
516                 
517                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
518                         return 0;
519         }
520         
521         demux = *our_demux;
522         return 0;
523 }
524
525 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
526 {
527         frontend = &m_frontend->get();
528         if (frontend)
529                 return 0;
530         else
531                 return -ENODEV;
532 }
533
534 RESULT eDVBChannel::playFile(const char *file)
535 {
536         ASSERT(!m_frontend);
537         if (m_pvr_thread)
538         {
539                 m_pvr_thread->stop();
540                 delete m_pvr_thread;
541                 m_pvr_thread = 0;
542         }
543         
544         m_tstools.openFile(file);
545         
546                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
547                    THEN DO A REAL FIX HERE! */
548         
549                 /* (this codepath needs to be improved anyway.) */
550         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
551         if (m_pvr_fd_dst < 0)
552         {
553                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)");
554                 return -ENODEV;
555         }
556         
557         m_pvr_fd_src = open(file, O_RDONLY);
558         if (m_pvr_fd_src < 0)
559         {
560                 eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
561                 close(m_pvr_fd_dst);
562                 return -ENOENT;
563         }
564         
565         m_state = state_ok;
566         m_stateChanged(this);
567         
568         m_pvr_thread = new eFilePushThread();
569         m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
570
571         return 0;
572 }
573
574 RESULT eDVBChannel::getLength(pts_t &len)
575 {
576         return m_tstools.calcLen(len);
577 }
578
579 RESULT eDVBChannel::getCurrentPosition(pts_t &pos)
580 {
581         if (!m_decoder_demux)
582                 return -1;
583         
584         off_t begin = 0;
585                 /* getPTS for offset 0 is cached, so it doesn't harm. */
586         int r = m_tstools.getPTS(begin, pos);
587         if (r)
588         {
589                 eDebug("tstools getpts(0) failed!");
590                 return r;
591         }
592         
593         pts_t now;
594         
595         r = m_decoder_demux->get().getSTC(now);
596
597         if (r)
598         {
599                 eDebug("demux getSTC failed");
600                 return -1;
601         }
602         
603 //      eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
604                 /* when we are less than 10 seconds before the start, return 0. */
605                 /* (we're just waiting for the timespam to start) */
606         if ((now < pos) && ((pos - now) < 90000 * 10))
607         {
608                 pos = 0;
609                 return 0;
610         }
611         
612         if (now < pos) /* wrap around */
613                 pos = now + ((pts_t)1)<<33 - pos;
614         else
615                 pos = now - pos;
616         
617         return 0;
618 }