after DECLARE_REF now all is private.. not public
[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/pmt.h>
6 #include <lib/dvb/sec.h>
7
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14
15 DEFINE_REF(eDVBRegisteredFrontend);
16 DEFINE_REF(eDVBRegisteredDemux);
17
18 DEFINE_REF(eDVBAllocatedFrontend);
19
20 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
21 {
22         m_fe->inc_use();
23 }
24
25 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
26 {
27         m_fe->dec_use();
28 }
29
30 DEFINE_REF(eDVBAllocatedDemux);
31
32 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
33 {
34         m_demux->m_inuse++;
35 }
36
37 eDVBAllocatedDemux::~eDVBAllocatedDemux()
38 {
39         --m_demux->m_inuse;
40 }
41
42 DEFINE_REF(eDVBResourceManager);
43
44 eDVBResourceManager *eDVBResourceManager::instance;
45
46 RESULT eDVBResourceManager::getInstance(ePtr<eDVBResourceManager> &ptr)
47 {
48         if (instance)
49         {
50                 ptr = instance;
51                 return 0;
52         }
53         return -1;
54 }
55
56 ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
57 {
58         ePtr<eDVBResourceManager> ptr;
59         eDVBResourceManager::getInstance(ptr);
60         return ptr;
61 }
62
63 eDVBResourceManager::eDVBResourceManager()
64         :m_releaseCachedChannelTimer(eApp)
65 {
66         avail = 1;
67         busy = 0;
68         m_sec = new eDVBSatelliteEquipmentControl(m_frontend);
69         if (!instance)
70                 instance = this;
71                 
72                 /* search available adapters... */
73
74                 // add linux devices
75         
76         int num_adapter = 0;
77         while (eDVBAdapterLinux::exist(num_adapter))
78         {
79                 addAdapter(new eDVBAdapterLinux(num_adapter));
80                 num_adapter++;
81         }
82         
83         eDebug("found %d adapter, %d frontends and %d demux", 
84                 m_adapter.size(), m_frontend.size(), m_demux.size());
85
86         eDVBCAService::registerChannelCallback(this);
87
88         CONNECT(m_releaseCachedChannelTimer.timeout, eDVBResourceManager::releaseCachedChannel);
89 }
90
91 void eDVBResourceManager::feStateChanged()
92 {
93         int mask=0;
94         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
95                 if (i->m_inuse)
96                         mask |= ( 1 << i->m_frontend->getSlotID() );
97         /* emit */ frontendUseMaskChanged(mask);
98 }
99
100 DEFINE_REF(eDVBAdapterLinux);
101 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
102 {
103                 // scan frontends
104         int num_fe = 0;
105         
106         eDebug("scanning for frontends..");
107         while (1)
108         {
109                 struct stat s;
110                 char filename[128];
111 #if HAVE_DVB_API_VERSION < 3
112                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
113 #else
114                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
115 #endif
116                 if (stat(filename, &s))
117                         break;
118                 ePtr<eDVBFrontend> fe;
119
120                 int ok = 0;
121                 fe = new eDVBFrontend(m_nr, num_fe, ok);
122                 if (ok)
123                         m_frontend.push_back(fe);
124                 ++num_fe;
125         }
126         
127                 // scan demux
128         int num_demux = 0;
129         while (1)
130         {
131                 struct stat s;
132                 char filename[128];
133 #if HAVE_DVB_API_VERSION < 3
134                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
135 #else
136                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
137 #endif
138                 if (stat(filename, &s))
139                         break;
140                 ePtr<eDVBDemux> demux;
141                 
142                 demux = new eDVBDemux(m_nr, num_demux);
143                 m_demux.push_back(demux);
144                         
145                 ++num_demux;
146         }
147 }
148
149 int eDVBAdapterLinux::getNumDemux()
150 {
151         return m_demux.size();
152 }
153
154 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
155 {
156         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
157         while (nr && (i != m_demux.end()))
158         {
159                 --nr;
160                 ++i;
161         }
162         
163         if (i != m_demux.end())
164                 demux = *i;
165         else
166                 return -1;
167                 
168         return 0;
169 }
170
171 int eDVBAdapterLinux::getNumFrontends()
172 {
173         return m_frontend.size();
174 }
175
176 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
177 {
178         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
179         while (nr && (i != m_frontend.end()))
180         {
181                 --nr;
182                 ++i;
183         }
184         
185         if (i != m_frontend.end())
186                 fe = *i;
187         else
188                 return -1;
189                 
190         return 0;
191 }
192
193 int eDVBAdapterLinux::exist(int nr)
194 {
195         struct stat s;
196         char filename[128];
197 #if HAVE_DVB_API_VERSION < 3
198         sprintf(filename, "/dev/dvb/card%d", nr);
199 #else
200         sprintf(filename, "/dev/dvb/adapter%d", nr);
201 #endif
202         if (!stat(filename, &s))
203                 return 1;
204         return 0;
205 }
206
207 eDVBResourceManager::~eDVBResourceManager()
208 {
209         if (instance == this)
210                 instance = 0;
211 }
212
213 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
214 {
215         int num_fe = adapter->getNumFrontends();
216         int num_demux = adapter->getNumDemux();
217         
218         m_adapter.push_back(adapter);
219         
220         int i;
221         for (i=0; i<num_demux; ++i)
222         {
223                 ePtr<eDVBDemux> demux;
224                 if (!adapter->getDemux(demux, i))
225                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
226         }
227
228         ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
229         for (i=0; i<num_fe; ++i)
230         {
231                 ePtr<eDVBFrontend> frontend;
232                 if (!adapter->getFrontend(frontend, i))
233                 {
234                         int frontendType=0;
235                         frontend->getFrontendType(frontendType);
236                         eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
237                         CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
238                         m_frontend.push_back(new_fe);
239                         frontend->setSEC(m_sec);
240                         // we must link all dvb-t frontends ( for active antenna voltage )
241                         if (frontendType == iDVBFrontend::feTerrestrial)
242                         {
243                                 if (prev_dvbt_frontend)
244                                 {
245                                         prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
246                                         frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
247                                 }
248                                 prev_dvbt_frontend = new_fe;
249                         }
250                 }
251         }
252 }
253
254 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
255 {
256         if (!PyList_Check(list))
257         {
258                 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
259                 return NULL;
260         }
261         if ((unsigned int)PyList_Size(list) != m_frontend.size())
262         {
263                 char blasel[256];
264                 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
265                         m_frontend.size(), PyList_Size(list));
266                 PyErr_SetString(PyExc_StandardError, blasel);
267                 return NULL;
268         }
269         int pos=0;
270         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
271         {
272                 ePyObject obj = PyList_GET_ITEM(list, pos++);
273                 if (!i->m_frontend->setSlotInfo(obj))
274                         return NULL;
275         }
276         Py_RETURN_NONE;
277 }
278
279 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm)
280 {
281         ePtr<eDVBRegisteredFrontend> best;
282         int bestval = 0;
283         int foundone = 0;
284
285         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
286         {
287                 int c = i->m_frontend->isCompatibleWith(feparm);
288
289                 if (c)  /* if we have at least one frontend which is compatible with the source, flag this. */
290                         foundone = 1;
291
292                 if (!i->m_inuse)
293                 {
294                         if (c > bestval)
295                         {
296                                 bestval = c;
297                                 best = i;
298                         }
299                 }
300         }
301
302         if (best)
303         {
304                 fe = new eDVBAllocatedFrontend(best);
305                 return 0;
306         }
307
308         fe = 0;
309
310         if (foundone)
311                 return errAllSourcesBusy;
312         else
313                 return errNoSourceFound;
314 }
315
316 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
317 {
318         int err = errNoSourceFound;
319         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
320                 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
321                 {
322                         // check if another slot linked to this is in use
323                         long tmp;
324                         i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
325                         if ( tmp != -1 )
326                         {
327                                 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
328                                 if (satpos_depends_to_fe->m_inuse)
329                                 {
330                                         eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
331                                         err = errAllSourcesBusy;
332                                         goto alloc_fe_by_id_not_possible;
333                                 }
334                         }
335                         else // check linked tuners
336                         {
337                                 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
338                                 while ( tmp != -1 )
339                                 {
340                                         eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
341                                         if (next->m_inuse)
342                                         {
343                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
344                                                 err = errAllSourcesBusy;
345                                                 goto alloc_fe_by_id_not_possible;
346                                         }
347                                         next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
348                                 }
349                                 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
350                                 while ( tmp != -1 )
351                                 {
352                                         eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
353                                         if (prev->m_inuse)
354                                         {
355                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
356                                                 err = errAllSourcesBusy;
357                                                 goto alloc_fe_by_id_not_possible;
358                                         }
359                                         prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
360                                 }
361                         }
362                         fe = new eDVBAllocatedFrontend(i);
363                         return 0;
364                 }
365 alloc_fe_by_id_not_possible:
366         fe = 0;
367         return err;
368 }
369
370 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
371 {
372                 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
373                    never use the first one unless we need a decoding demux. */
374
375         eDebug("allocate demux");
376         eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
377         
378         if (i == m_demux.end())
379                 return -1;
380                 
381         int n=0;
382                 /* FIXME: hardware demux policy */
383         if (!(cap & iDVBChannel::capDecode))
384         {
385                 if (m_demux.size() > 2)  /* assumed to be true, otherwise we have lost anyway */
386                 {
387                         ++i, ++n;
388                         ++i, ++n;
389                 }
390         }
391         
392         for (; i != m_demux.end(); ++i, ++n)
393         {
394                 int is_decode = n < 2;
395                 
396                 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
397                 
398                 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
399                 {
400                         if ((cap & iDVBChannel::capDecode) && !is_decode)
401                                 continue;
402                         
403                         demux = new eDVBAllocatedDemux(i);
404                         if (fe)
405                                 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
406                         else
407                                 demux->get().setSourcePVR(0);
408                         return 0;
409                 }
410         }
411         eDebug("demux not found");
412         return -1;
413 }
414
415 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
416 {
417         m_list = list;
418         return 0;
419 }
420
421 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
422 {
423         list = m_list;
424         if (list)
425                 return 0;
426         else
427                 return -ENOENT;
428 }
429
430 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
431 {
432                 /* first, check if a channel is already existing. */
433
434         if (m_cached_channel)
435         {
436                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
437                 if(channelid==cache_chan->getChannelID())
438                 {
439                         eDebug("use cached_channel");
440                         channel = m_cached_channel;
441                         return 0;
442                 }
443                 m_cached_channel_state_changed_conn.disconnect();
444                 m_cached_channel=0;
445                 m_releaseCachedChannelTimer.stop();
446         }
447
448 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
449         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
450         {
451 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
452                 if (i->m_channel_id == channelid)
453                 {
454 //                      eDebug("found shared channel..");
455                         channel = i->m_channel;
456                         return 0;
457                 }
458         }
459         
460         /* no currently available channel is tuned to this channelid. create a new one, if possible. */
461
462         if (!m_list)
463         {
464                 eDebug("no channel list set!");
465                 return errNoChannelList;
466         }
467
468         ePtr<iDVBFrontendParameters> feparm;
469         if (m_list->getChannelFrontendData(channelid, feparm))
470         {
471                 eDebug("channel not found!");
472                 return errChannelNotInList;
473         }
474
475         /* allocate a frontend. */
476         
477         ePtr<eDVBAllocatedFrontend> fe;
478
479         int err = allocateFrontend(fe, feparm);
480         if (err)
481                 return err;
482
483         RESULT res;
484         ePtr<eDVBChannel> ch;
485         ch = new eDVBChannel(this, fe);
486
487         res = ch->setChannel(channelid, feparm);
488         if (res)
489         {
490                 channel = 0;
491                 return errChidNotFound;
492         }
493         m_cached_channel = channel = ch;
494         m_cached_channel_state_changed_conn =
495                 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
496
497         return 0;
498 }
499
500 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
501 {
502         int state=0;
503         chan->getState(state);
504         switch (state)
505         {
506                 case iDVBChannel::state_release:
507                 case iDVBChannel::state_ok:
508                 {
509                         eDebug("stop release channel timer");
510                         m_releaseCachedChannelTimer.stop();
511                         break;
512                 }
513                 case iDVBChannel::state_last_instance:
514                 {
515                         eDebug("start release channel timer");
516                         m_releaseCachedChannelTimer.start(3000, true);
517                         break;
518                 }
519                 default: // ignore all other events
520                         break;
521         }
522 }
523
524 void eDVBResourceManager::releaseCachedChannel()
525 {
526         eDebug("release cached channel (timer timeout)");
527         m_cached_channel=0;
528 }
529
530 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
531 {
532         ePtr<eDVBAllocatedFrontend> fe;
533
534         if (m_cached_channel)
535         {
536                 m_cached_channel_state_changed_conn.disconnect();
537                 m_cached_channel=0;
538                 m_releaseCachedChannelTimer.stop();
539         }
540
541         int err = allocateFrontendByIndex(fe, slot_index);
542         if (err)
543                 return err;
544
545         eDVBChannel *ch;
546         ch = new eDVBChannel(this, fe);
547
548         channel = ch;
549         return 0;
550 }
551
552
553 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
554 {
555         ePtr<eDVBAllocatedDemux> demux;
556
557         if (m_cached_channel && m_releaseCachedChannelTimer.isActive())
558         {
559                 m_cached_channel_state_changed_conn.disconnect();
560                 m_cached_channel=0;
561                 m_releaseCachedChannelTimer.stop();
562         }
563
564         eDVBChannel *ch;
565         ch = new eDVBChannel(this, 0);
566
567         channel = ch;
568         return 0;
569 }
570
571 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
572 {
573         m_active_channels.push_back(active_channel(chid, ch));
574         /* emit */ m_channelAdded(ch);
575         return 0;
576 }
577
578 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
579 {
580         int cnt = 0;
581         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
582         {
583                 if (i->m_channel == ch)
584                 {
585                         i = m_active_channels.erase(i);
586                         ++cnt;
587                 } else
588                         ++i;
589         }
590         ASSERT(cnt == 1);
591         if (cnt == 1)
592                 return 0;
593         return -ENOENT;
594 }
595
596 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
597 {
598         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
599         return 0;
600 }
601
602 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm)
603 {
604         ePtr<eDVBRegisteredFrontend> best;
605         int bestval = 0;
606
607         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
608                 if (!i->m_inuse)
609                 {
610                         int c = i->m_frontend->isCompatibleWith(feparm);
611                         if (c > bestval)
612                                 bestval = c;
613                 }
614         return bestval;
615 }
616
617 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
618 {
619         if (channellist)
620         {
621                 ePtr<iDVBFrontendParameters> feparm;
622                 if (!channellist->getChannelFrontendData(chid, feparm))
623                 {
624                         int system;
625                         if (!feparm->getSystem(system))
626                         {
627                                 switch(system)
628                                 {
629                                         case iDVBFrontend::feSatellite:
630                                                 return 50000;
631                                         case iDVBFrontend::feCable:
632                                                 return 40000;
633                                         case iDVBFrontend::feTerrestrial:
634                                                 return 30000;
635                                         default:
636                                                 break;
637                                 }
638                         }
639                 }
640         }
641         return 0;
642 }
643
644 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
645 {
646         int ret=0;
647         if (m_cached_channel)
648         {
649                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
650                 if(channelid==cache_chan->getChannelID())
651                         return tuner_type_channel_default(m_list, channelid);
652         }
653
654                 /* first, check if a channel is already existing. */
655 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
656         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
657         {
658 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
659                 if (i->m_channel_id == channelid)
660                 {
661 //                      eDebug("found shared channel..");
662                         return tuner_type_channel_default(m_list, channelid);
663                 }
664         }
665
666         int *decremented_cached_channel_fe_usecount=NULL,
667                 *decremented_fe_usecount=NULL;
668
669         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
670         {
671 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
672                 if (i->m_channel_id == ignore)
673                 {
674                         eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
675                         // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
676                         // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
677                         // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
678                         // or 2 when the cached channel is not equal to the compared channel
679                         if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2)  // channel only used once..
680                         {
681                                 ePtr<iDVBFrontend> fe;
682                                 if (!i->m_channel->getFrontend(fe))
683                                 {
684                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
685                                         {
686                                                 if ( &(*fe) == &(*ii->m_frontend) )
687                                                 {
688                                                         --ii->m_inuse;
689                                                         decremented_fe_usecount = &ii->m_inuse;
690                                                         if (channel == &(*m_cached_channel))
691                                                                 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
692                                                         break;
693                                                 }
694                                         }
695                                 }
696                         }
697                         break;
698                 }
699         }
700
701         if (!decremented_cached_channel_fe_usecount)
702         {
703                 if (m_cached_channel)
704                 {
705                         eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
706                         if (channel->getUseCount() == 1)
707                         {
708                                 ePtr<iDVBFrontend> fe;
709                                 if (!channel->getFrontend(fe))
710                                 {
711                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
712                                         {
713                                                 if ( &(*fe) == &(*ii->m_frontend) )
714                                                 {
715                                                         --ii->m_inuse;
716                                                         decremented_cached_channel_fe_usecount = &ii->m_inuse;
717                                                         break;
718                                                 }
719                                         }
720                                 }
721                         }
722                 }
723         }
724         else
725                 decremented_cached_channel_fe_usecount=NULL;
726
727         ePtr<iDVBFrontendParameters> feparm;
728
729         if (!m_list)
730         {
731                 eDebug("no channel list set!");
732                 goto error;
733         }
734
735         if (m_list->getChannelFrontendData(channelid, feparm))
736         {
737                 eDebug("channel not found!");
738                 goto error;
739         }
740
741         ret = canAllocateFrontend(feparm);
742
743 error:
744         if (decremented_fe_usecount)
745                 ++(*decremented_fe_usecount);
746         if (decremented_cached_channel_fe_usecount)
747                 ++(*decremented_cached_channel_fe_usecount);
748
749         return ret;
750 }
751
752 bool eDVBResourceManager::canMeasureFrontendInputPower()
753 {
754         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
755         {
756                 return i->m_frontend->readInputpower() >= 0;
757         }
758         return false;
759 }
760
761 class eDVBChannelFilePush: public eFilePushThread
762 {
763 public:
764         eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
765         void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
766
767                         /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
768                         /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
769         void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
770 protected:
771         int m_iframe_search, m_iframe_state, m_pid;
772         int m_timebase_change;
773         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
774 };
775
776 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t &current_span_remaining)
777 {
778 #if 0
779         if (m_timebase_change)
780         {
781                 eDebug("timebase change: %d", m_timebase_change);
782                 int offset;
783                 for (offset = 0; offset < len; offset += 188)
784                 {
785                         unsigned char *pkt = (unsigned char*)_data + offset;
786                         if (pkt[1] & 0x40) /* pusi */
787                         {
788                                 if (pkt[3] & 0x20) // adaption field present?
789                                         pkt += pkt[4] + 4 + 1;  /* skip adaption field and header */
790                                 else
791                                         pkt += 4; /* skip header */
792                                 if (pkt[0] || pkt[1] || (pkt[2] != 1))
793                                 {
794                                         eWarning("broken startcode");
795                                         continue;
796                                 }
797
798                                 pts_t pts = 0;
799
800                                 if (pkt[7] & 0x80) // PTS present?
801                                 {
802                                         pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
803                                         pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
804                                         pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
805                                         pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
806                                         pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
807
808 #if 0
809                                         off_t off = 0;
810                                         RESULT r = m_tstools.fixupPTS(off, pts);
811                                         if (r)
812                                                 eWarning("fixup PTS while trickmode playback failed.\n");
813 #endif
814
815                                         int sec = pts / 90000;
816                                         int frm = pts % 90000;
817                                         int min = sec / 60;
818                                         sec %= 60;
819                                         int hr = min / 60;
820                                         min %= 60;
821                                         int d = hr / 24;
822                                         hr %= 24;
823
824 //                                      eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
825
826                                         pts += 0x80000000LL;
827                                         pts *= m_timebase_change;
828                                         pts >>= 16;
829
830                                         sec = pts / 90000;
831                                         frm = pts % 90000;
832                                         min = sec / 60;
833                                         sec %= 60;
834                                         hr = min / 60;
835                                         min %= 60;
836                                         d = hr / 24;
837                                         hr %= 24;
838
839 //                                      eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
840
841                                         pkt[9] &= ~0xE;
842                                         pkt[10] = 0;
843                                         pkt[11] &= ~1;
844                                         pkt[12] = 0;
845                                         pkt[13] &= ~1;
846
847                                         pkt[9]  |= (pts >> 29) & 0xE;
848                                         pkt[10] |= (pts >> 22) & 0xFF;
849                                         pkt[11] |= (pts >> 14) & 0xFE;
850                                         pkt[12] |= (pts >> 7) & 0xFF;
851                                         pkt[13] |= (pts << 1) & 0xFE;
852                                 }
853                         }
854                 }
855         }
856 #endif
857
858 #if 1 /* not yet */
859         if (!m_iframe_search)
860                 return len;
861
862         unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
863
864 //      eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
865
866         unsigned char *d = data;
867         while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
868         {
869                 int offset = d - data;
870                 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
871                 unsigned char *ts = data + ts_offset;
872                 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
873
874                 if ((d[3] == 0) && (m_pid == pid))  /* picture start */
875                 {
876                         int picture_type = (d[5] >> 3) & 7;
877                         d += 4;
878
879 //                      eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
880
881                         if (m_iframe_state == 1)
882                         {
883                                         /* we are allowing data, and stop allowing data on the next frame. 
884                                            we now found a frame. so stop here. */
885                                 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
886                                 current_span_remaining = 0;
887                                 m_iframe_state = 0;
888                                 unsigned char *fts = ts + 188;
889                                 while (fts < (data + len))
890                                 {
891                                         fts[1] |= 0x1f;
892                                         fts[2] |= 0xff; /* drop packet */
893                                         fts += 188;
894                                 }
895
896                                 return len; // ts_offset + 188; /* deliver this packet, but not more. */
897                         } else
898                         {
899                                 if (picture_type != 1) /* we are only interested in I frames */
900                                         continue;
901
902                                 unsigned char *fts = data;
903                                 while (fts < ts)
904                                 {
905                                         fts[1] |= 0x1f;
906                                         fts[2] |= 0xff; /* drop packet */
907
908                                         fts += 188;
909                                 }
910                                                 /* force payload only */
911                                 ts[3] &= ~0x30;
912                                 ts[3] |=  0x10;
913
914 //                              memset(ts + 4, 0xFF, (offset % 188) - 4);
915
916                                 m_iframe_state = 1;
917                         }
918                 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
919                 {
920                         if (m_pid != pid)
921                         {
922                                 eDebug("now locked to pid %04x", pid);
923                                 m_pid = pid;
924                         }
925 //                      m_pid = 0x6e;
926                         d += 4;
927                 } else
928                         d += 4; /* ignore */
929
930         }
931
932         if (m_iframe_state == 1)
933                 return len;
934         else
935                 return 0; /* we need find an iframe first */
936 #else
937         return len;
938 #endif
939 }
940
941 DEFINE_REF(eDVBChannel);
942
943 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
944 {
945         m_frontend = frontend;
946
947         m_pvr_thread = 0;
948         
949         m_skipmode_n = m_skipmode_m = 0;
950         
951         if (m_frontend)
952                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
953 }
954
955 eDVBChannel::~eDVBChannel()
956 {
957         if (m_channel_id)
958                 m_mgr->removeChannel(this);
959
960         stopFile();
961 }
962
963 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
964 {
965         int state, ourstate = 0;
966         
967                 /* if we are already in shutdown, don't change state. */
968         if (m_state == state_release)
969                 return;
970         
971         if (fe->getState(state))
972                 return;
973         
974         if (state == iDVBFrontend::stateLock)
975         {
976                 eDebug("OURSTATE: ok");
977                 ourstate = state_ok;
978         } else if (state == iDVBFrontend::stateTuning)
979         {
980                 eDebug("OURSTATE: tuning");
981                 ourstate = state_tuning;
982         } else if (state == iDVBFrontend::stateLostLock)
983         {
984                         /* on managed channels, we try to retune in order to re-acquire lock. */
985                 if (m_current_frontend_parameters)
986                 {
987                         eDebug("OURSTATE: lost lock, trying to retune");
988                         ourstate = state_tuning;
989                         m_frontend->get().tune(*m_current_frontend_parameters);
990                 } else
991                         /* on unmanaged channels, we don't do this. the client will do this. */
992                 {
993                         eDebug("OURSTATE: lost lock, unavailable now.");
994                         ourstate = state_unavailable;
995                 }
996         } else if (state == iDVBFrontend::stateFailed)
997         {
998                 eDebug("OURSTATE: failed");
999                 ourstate = state_failed;
1000         } else
1001                 eFatal("state unknown");
1002         
1003         if (ourstate != m_state)
1004         {
1005                 m_state = ourstate;
1006                 m_stateChanged(this);
1007         }
1008 }
1009
1010 void eDVBChannel::pvrEvent(int event)
1011 {
1012         switch (event)
1013         {
1014         case eFilePushThread::evtEOF:
1015                 eDebug("eDVBChannel: End of file!");
1016                 m_event(this, evtEOF);
1017                 break;
1018         case eFilePushThread::evtUser: /* start */
1019                 eDebug("SOF");
1020                 m_event(this, evtSOF);
1021                 break;
1022         }
1023 }
1024
1025 void eDVBChannel::cueSheetEvent(int event)
1026 {
1027                 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1028         if (!m_pvr_thread)
1029                 return;
1030         switch (event)
1031         {
1032         case eCueSheet::evtSeek:
1033                 eDebug("seek.");
1034                 flushPVR(m_cue->m_decoding_demux);
1035                 break;
1036         case eCueSheet::evtSkipmode:
1037         {
1038                 {
1039                         m_cue->m_lock.WrLock();
1040                         m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1041                         m_cue->m_lock.Unlock();
1042                         eRdLocker l(m_cue->m_lock);
1043                         if (m_cue->m_skipmode_ratio)
1044                         {
1045                                 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1046                                 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1047                                                 /* i agree that this might look a bit like black magic. */
1048                                 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1049                                 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1050
1051                                 if (m_cue->m_skipmode_ratio < 0)
1052                                         m_skipmode_m -= m_skipmode_n;
1053
1054                                 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1055
1056                                 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1057                                 {
1058                                         eWarning("something is wrong with this calculation");
1059                                         m_skipmode_n = m_skipmode_m = 0;
1060                                 }
1061                         } else
1062                         {
1063                                 eDebug("skipmode ratio is 0, normal play");
1064                                 m_skipmode_n = m_skipmode_m = 0;
1065                         }
1066                 }
1067                 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1068                 if (m_cue->m_skipmode_ratio != 0)
1069                         m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1070                 else
1071                         m_pvr_thread->setTimebaseChange(0); /* normal playback */
1072                 eDebug("flush pvr");
1073                 flushPVR(m_cue->m_decoding_demux);
1074                 eDebug("done");
1075                 break;
1076         }
1077         case eCueSheet::evtSpanChanged:
1078         {
1079                 m_source_span.clear();
1080                 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1081                 {
1082                         off_t offset_in, offset_out;
1083                         pts_t pts_in = i->first, pts_out = i->second;
1084                         if (m_tstools.getOffset(offset_in, pts_in) || m_tstools.getOffset(offset_out, pts_out))
1085                         {
1086                                 eDebug("span translation failed.\n");
1087                                 continue;
1088                         }
1089                         eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1090                         m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1091                 }
1092                 break;
1093         }
1094         }
1095 }
1096
1097         /* align toward zero */
1098 static inline long long align(long long x, int align)
1099 {
1100         int sign = x < 0;
1101
1102         if (sign)
1103                 x = -x;
1104
1105         x -= x % align;
1106
1107         if (sign)
1108                 x = -x;
1109
1110         return x;
1111 }
1112
1113         /* remember, this gets called from another thread. */
1114 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1115 {
1116         const int blocksize = 188;
1117         unsigned int max = align(10*1024*1024, blocksize);
1118         current_offset = align(current_offset, blocksize);
1119         
1120         if (!m_cue)
1121         {
1122                 eDebug("no cue sheet. forcing normal play");
1123                 start = current_offset;
1124                 size = max;
1125                 return;
1126         }
1127
1128         m_cue->m_lock.RdLock();
1129         if (!m_cue->m_decoding_demux)
1130         {
1131                 start = current_offset;
1132                 size = max;
1133                 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1134                 m_cue->m_lock.Unlock();
1135                 return;
1136         }
1137
1138         if (m_skipmode_n)
1139         {
1140                 eDebug("skipmode %d:%d", m_skipmode_m, m_skipmode_n);
1141                 max = align(m_skipmode_n, blocksize);
1142         }
1143
1144         eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1145
1146         current_offset += align(m_skipmode_m, blocksize);
1147
1148         while (!m_cue->m_seek_requests.empty())
1149         {
1150                 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1151                 m_cue->m_lock.Unlock();
1152                 m_cue->m_lock.WrLock();
1153                 m_cue->m_seek_requests.pop_front();
1154                 m_cue->m_lock.Unlock();
1155                 m_cue->m_lock.RdLock();
1156                 int relative = seek.first;
1157                 pts_t pts = seek.second;
1158
1159                 pts_t now = 0;
1160                 if (relative)
1161                 {
1162                         if (!m_cue->m_decoder)
1163                         {
1164                                 eDebug("no decoder - can't seek relative");
1165                                 continue;
1166                         }
1167                         if (m_cue->m_decoder->getPTS(0, now))
1168                         {
1169                                 eDebug("decoder getPTS failed, can't seek relative");
1170                                 continue;
1171                         }
1172                         if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1173                         {
1174                                 eDebug("seekTo: getCurrentPosition failed!");
1175                                 continue;
1176                         }
1177                 } else if (pts < 0) /* seek relative to end */
1178                 {
1179                         pts_t len;
1180                         if (!getLength(len))
1181                         {
1182                                 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1183                                 pts += len;
1184                         } else
1185                         {
1186                                 eWarning("getLength failed - can't seek relative to end!");
1187                                 continue;
1188                         }
1189                 }
1190                 
1191                 if (relative == 1) /* pts relative */
1192                 {
1193                         pts += now;
1194                         if (pts < 0)
1195                                 pts = 0;
1196                 }
1197
1198                 if (relative != 2)
1199                         if (pts < 0)
1200                                 pts = 0;
1201                 
1202                 if (relative == 2) /* AP relative */
1203                 {
1204                         eDebug("AP relative seeking: %lld, at %lld", pts, now);
1205                         pts_t nextap;
1206                         if (m_tstools.getNextAccessPoint(nextap, now, pts))
1207                         {
1208                                 pts = now - 90000; /* approx. 1s */
1209                                 eDebug("AP relative seeking failed!");
1210                         } else
1211                         {
1212                                 eDebug("next ap is %llx\n", pts);
1213                                 pts = nextap;
1214                         }
1215                 }
1216                 
1217                 off_t offset = 0;
1218                 if (m_tstools.getOffset(offset, pts))
1219                 {
1220                         eDebug("get offset for pts=%lld failed!", pts);
1221                         continue;
1222                 }
1223
1224                 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1225                 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1226         }
1227
1228         m_cue->m_lock.Unlock();
1229
1230         for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1231         {
1232                 long long aligned_start = align(i->first, blocksize);
1233                 long long aligned_end = align(i->second, blocksize);
1234         
1235                 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1236                 {
1237                         start = current_offset;
1238                                 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1239                         if ((aligned_end - current_offset) > max)
1240                                 size = max;
1241                         else
1242                                 size = aligned_end - current_offset;
1243                         eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1244                         return;
1245                 }
1246                 if (current_offset < aligned_start)
1247                 {
1248                                 /* ok, our current offset is in an 'out' zone. */
1249                         if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1250                         {
1251                                         /* in normal playback, just start at the next zone. */
1252                                 start = i->first;
1253
1254                                         /* size is not 64bit! */
1255                                 if ((i->second - i->first) > max)
1256                                         size = max;
1257                                 else
1258                                         size = aligned_end - aligned_start;
1259
1260                                 eDebug("skip");
1261                                 if (m_skipmode_m < 0)
1262                                 {
1263                                         eDebug("reached SOF");
1264                                                 /* reached SOF */
1265                                         m_skipmode_m = 0;
1266                                         m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1267                                 }
1268                         } else
1269                         {
1270                                         /* when skipping reverse, however, choose the zone before. */
1271                                 --i;
1272                                 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1273                                 size_t len;
1274
1275                                 aligned_start = align(i->first, blocksize);
1276                                 aligned_end = align(i->second, blocksize);
1277
1278                                 if ((aligned_end - aligned_start) > max)
1279                                         len = max;
1280                                 else
1281                                         len = aligned_end - aligned_start;
1282
1283                                 start = aligned_end - len;
1284                                 eDebug("skipping to %llx, %d", start, len);
1285                         }
1286
1287                         eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1288                         return;
1289                 }
1290         }
1291
1292         if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1293         {
1294                 eDebug("reached SOF");
1295                 m_skipmode_m = 0;
1296                 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1297         }
1298
1299         start = current_offset;
1300         size = max;
1301
1302         eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
1303         return;
1304 }
1305
1306 void eDVBChannel::AddUse()
1307 {
1308         if (++m_use_count > 1 && m_state == state_last_instance)
1309         {
1310                 m_state = state_ok;
1311                 m_stateChanged(this);
1312         }
1313 }
1314
1315 void eDVBChannel::ReleaseUse()
1316 {
1317         if (!--m_use_count)
1318         {
1319                 m_state = state_release;
1320                 m_stateChanged(this);
1321         }
1322         else if (m_use_count == 1)
1323         {
1324                 m_state = state_last_instance;
1325                 m_stateChanged(this);
1326         }
1327 }
1328
1329 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1330 {
1331         if (m_channel_id)
1332                 m_mgr->removeChannel(this);
1333                 
1334         if (!channelid)
1335                 return 0;
1336
1337         if (!m_frontend)
1338         {
1339                 eDebug("no frontend to tune!");
1340                 return -ENODEV;
1341         }
1342         
1343         m_channel_id = channelid;
1344         m_mgr->addChannel(channelid, this);
1345         m_state = state_tuning;
1346                         /* if tuning fails, shutdown the channel immediately. */
1347         int res;
1348         res = m_frontend->get().tune(*feparm);
1349         m_current_frontend_parameters = feparm;
1350         
1351         if (res)
1352         {
1353                 m_state = state_release;
1354                 m_stateChanged(this);
1355                 return res;
1356         }
1357         
1358         return 0;
1359 }
1360
1361 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1362 {
1363         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1364         return 0;
1365 }
1366
1367 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1368 {
1369         connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1370         return 0;
1371 }
1372
1373 RESULT eDVBChannel::getState(int &state)
1374 {
1375         state = m_state;
1376         return 0;
1377 }
1378
1379 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1380 {
1381         return -1;
1382 }
1383
1384 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1385 {
1386         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1387         
1388         if (!our_demux)
1389         {
1390                 demux = 0;
1391                 
1392                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1393                         return -1;
1394         }
1395         
1396         demux = *our_demux;
1397                 /* don't hold a reference to the decoding demux, we don't need it. */
1398                 
1399                 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1400                    the refcount is lost. thus, decoding demuxes are never allocated. 
1401                    
1402                    this poses a big problem for PiP. */
1403         if (cap & capDecode)
1404                 our_demux = 0;
1405         return 0;
1406 }
1407
1408 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1409 {
1410         frontend = 0;
1411         if (!m_frontend)
1412                 return -ENODEV;
1413         frontend = &m_frontend->get();
1414         if (frontend)
1415                 return 0;
1416         return -ENODEV;
1417 }
1418
1419 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &param)
1420 {
1421         param = m_current_frontend_parameters;
1422         return 0;
1423 }
1424
1425 RESULT eDVBChannel::playFile(const char *file)
1426 {
1427         ASSERT(!m_frontend);
1428         if (m_pvr_thread)
1429         {
1430                 m_pvr_thread->stop();
1431                 delete m_pvr_thread;
1432                 m_pvr_thread = 0;
1433         }
1434         
1435         m_tstools.openFile(file);
1436         
1437                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1438                    THEN DO A REAL FIX HERE! */
1439         
1440                 /* (this codepath needs to be improved anyway.) */
1441 #if HAVE_DVB_API_VERSION < 3
1442         m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1443 #else
1444         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1445 #endif
1446         if (m_pvr_fd_dst < 0)
1447         {
1448                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1449                 return -ENODEV;
1450         }
1451
1452         m_pvr_thread = new eDVBChannelFilePush();
1453         m_pvr_thread->enablePVRCommit(1);
1454         m_pvr_thread->setStreamMode(1);
1455         m_pvr_thread->setScatterGather(this);
1456
1457         if (m_pvr_thread->start(file, m_pvr_fd_dst))
1458         {
1459                 delete m_pvr_thread;
1460                 m_pvr_thread = 0;
1461                 eDebug("can't open PVR file %s (%m)", file);
1462                 return -ENOENT;
1463         }
1464         CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1465
1466         m_state = state_ok;
1467         m_stateChanged(this);
1468
1469         return 0;
1470 }
1471
1472 void eDVBChannel::stopFile()
1473 {
1474         if (m_pvr_thread)
1475         {
1476                 m_pvr_thread->stop();
1477                 ::close(m_pvr_fd_dst);
1478                 delete m_pvr_thread;
1479                 m_pvr_thread = 0;
1480         }
1481 }
1482
1483 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1484 {
1485         m_conn_cueSheetEvent = 0;
1486         m_cue = cuesheet;
1487         if (m_cue)
1488                 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1489 }
1490
1491 RESULT eDVBChannel::getLength(pts_t &len)
1492 {
1493         return m_tstools.calcLen(len);
1494 }
1495
1496 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1497 {
1498         if (!decoding_demux)
1499                 return -1;
1500         
1501         pts_t now;
1502         
1503         int r;
1504         
1505         if (mode == 0) /* demux */
1506         {
1507                 r = decoding_demux->getSTC(now, 0);
1508                 if (r)
1509                 {
1510                         eDebug("demux getSTC failed");
1511                         return -1;
1512                 }
1513         } else
1514                 now = pos; /* fixup supplied */
1515         
1516         off_t off = 0; /* TODO: fixme */
1517         r = m_tstools.fixupPTS(off, now);
1518         if (r)
1519         {
1520                 eDebug("fixup PTS failed");
1521                 return -1;
1522         }
1523         
1524         pos = now;
1525         
1526         return 0;
1527 }
1528
1529 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1530 {
1531                         /* when seeking, we have to ensure that all buffers are flushed.
1532                            there are basically 3 buffers:
1533                            a.) the filepush's internal buffer
1534                            b.) the PVR buffer (before demux)
1535                            c.) the ratebuffer (after demux)
1536                            
1537                            it's important to clear them in the correct order, otherwise
1538                            the ratebuffer (for example) would immediately refill from
1539                            the not-yet-flushed PVR buffer.
1540                         */
1541
1542         m_pvr_thread->pause();
1543                 /* flush internal filepush buffer */
1544         m_pvr_thread->flush();
1545                 /* HACK: flush PVR buffer */
1546         ::ioctl(m_pvr_fd_dst, 0);
1547         
1548                 /* flush ratebuffers (video, audio) */
1549         if (decoding_demux)
1550                 decoding_demux->flush();
1551
1552                 /* demux will also flush all decoder.. */
1553                 /* resume will re-query the SG */
1554         m_pvr_thread->resume();
1555 }
1556
1557 DEFINE_REF(eCueSheet);
1558
1559 eCueSheet::eCueSheet()
1560 {
1561         m_skipmode_ratio = 0;
1562 }
1563
1564 void eCueSheet::seekTo(int relative, const pts_t &pts)
1565 {
1566         m_lock.WrLock();
1567         m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1568         m_lock.Unlock();
1569         m_event(evtSeek);
1570 }
1571         
1572 void eCueSheet::clear()
1573 {
1574         m_lock.WrLock();
1575         m_spans.clear();
1576         m_lock.Unlock();
1577 }
1578
1579 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1580 {
1581         assert(begin < end);
1582         m_lock.WrLock();
1583         m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1584         m_lock.Unlock();
1585 }
1586
1587 void eCueSheet::commitSpans()
1588 {
1589         m_event(evtSpanChanged);
1590 }
1591
1592 void eCueSheet::setSkipmode(const pts_t &ratio)
1593 {
1594         m_lock.WrLock();
1595         m_skipmode_ratio = ratio;
1596         m_lock.Unlock();
1597         m_event(evtSkipmode);
1598 }
1599
1600 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1601 {
1602         m_decoding_demux = demux;
1603         m_decoder = decoder;
1604 }
1605
1606 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1607 {
1608         connection = new eConnection(this, m_event.connect(event));
1609         return 0;
1610 }