f04dac0b908dc90f341aa3e5cb314b87e55820e6
[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         int n=0;
379
380         if (i == m_demux.end())
381                 return -1;
382         
383         ePtr<eDVBRegisteredDemux> unused;
384         
385         if (m_demux.size() < 5)
386         {
387                 /* FIXME: hardware demux policy */
388                 if (!(cap & iDVBChannel::capDecode))
389                 {
390                         if (m_demux.size() > 2)  /* assumed to be true, otherwise we have lost anyway */
391                         {
392                                 ++i, ++n;
393                                 ++i, ++n;
394                         }
395                 }
396
397                 for (; i != m_demux.end(); ++i, ++n)
398                 {
399                         int is_decode = n < 2;
400                 
401                         int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
402                 
403                         if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
404                         {
405                                 if ((cap & iDVBChannel::capDecode) && !is_decode)
406                                         continue;
407                                 unused = i;     
408                                 break;
409                         }
410                 }
411         }
412         else // we asume dm8000
413         {
414                 for (; i != m_demux.end(); ++i, ++n)
415                 {
416                         if (fe)
417                         {
418                                 if (!i->m_inuse)
419                                 {
420                                         if (!unused)
421                                                 unused = i;
422                                 }
423                                 else if (i->m_adapter == fe->m_adapter && 
424                                     i->m_demux->getSource() == fe->m_frontend->getDVBID())
425                                 {
426                                         demux = new eDVBAllocatedDemux(i);
427                                         return 0;
428                                 }
429                         }
430                         else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
431                         {
432                                 if (i->m_inuse) {
433                                         demux = new eDVBAllocatedDemux(i);
434                                         return 0;
435                                 }
436                                 unused = i;
437                         }
438                 }
439         }
440
441         if (unused)
442         {
443                 demux = new eDVBAllocatedDemux(unused);
444                 if (fe)
445                         demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
446                 else
447                         demux->get().setSourcePVR(0);
448                 return 0;
449         }
450
451         eDebug("demux not found");
452         return -1;
453 }
454
455 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
456 {
457         m_list = list;
458         return 0;
459 }
460
461 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
462 {
463         list = m_list;
464         if (list)
465                 return 0;
466         else
467                 return -ENOENT;
468 }
469
470 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
471 {
472                 /* first, check if a channel is already existing. */
473
474         if (m_cached_channel)
475         {
476                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
477                 if(channelid==cache_chan->getChannelID())
478                 {
479                         eDebug("use cached_channel");
480                         channel = m_cached_channel;
481                         return 0;
482                 }
483                 m_cached_channel_state_changed_conn.disconnect();
484                 m_cached_channel=0;
485                 m_releaseCachedChannelTimer.stop();
486         }
487
488 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
489         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
490         {
491 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
492                 if (i->m_channel_id == channelid)
493                 {
494 //                      eDebug("found shared channel..");
495                         channel = i->m_channel;
496                         return 0;
497                 }
498         }
499         
500         /* no currently available channel is tuned to this channelid. create a new one, if possible. */
501
502         if (!m_list)
503         {
504                 eDebug("no channel list set!");
505                 return errNoChannelList;
506         }
507
508         ePtr<iDVBFrontendParameters> feparm;
509         if (m_list->getChannelFrontendData(channelid, feparm))
510         {
511                 eDebug("channel not found!");
512                 return errChannelNotInList;
513         }
514
515         /* allocate a frontend. */
516         
517         ePtr<eDVBAllocatedFrontend> fe;
518
519         int err = allocateFrontend(fe, feparm);
520         if (err)
521                 return err;
522
523         RESULT res;
524         ePtr<eDVBChannel> ch;
525         ch = new eDVBChannel(this, fe);
526
527         res = ch->setChannel(channelid, feparm);
528         if (res)
529         {
530                 channel = 0;
531                 return errChidNotFound;
532         }
533         m_cached_channel = channel = ch;
534         m_cached_channel_state_changed_conn =
535                 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
536
537         return 0;
538 }
539
540 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
541 {
542         int state=0;
543         chan->getState(state);
544         switch (state)
545         {
546                 case iDVBChannel::state_release:
547                 case iDVBChannel::state_ok:
548                 {
549                         eDebug("stop release channel timer");
550                         m_releaseCachedChannelTimer.stop();
551                         break;
552                 }
553                 case iDVBChannel::state_last_instance:
554                 {
555                         eDebug("start release channel timer");
556                         m_releaseCachedChannelTimer.start(3000, true);
557                         break;
558                 }
559                 default: // ignore all other events
560                         break;
561         }
562 }
563
564 void eDVBResourceManager::releaseCachedChannel()
565 {
566         eDebug("release cached channel (timer timeout)");
567         m_cached_channel=0;
568 }
569
570 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
571 {
572         ePtr<eDVBAllocatedFrontend> fe;
573
574         if (m_cached_channel)
575         {
576                 m_cached_channel_state_changed_conn.disconnect();
577                 m_cached_channel=0;
578                 m_releaseCachedChannelTimer.stop();
579         }
580
581         int err = allocateFrontendByIndex(fe, slot_index);
582         if (err)
583                 return err;
584
585         eDVBChannel *ch;
586         ch = new eDVBChannel(this, fe);
587
588         channel = ch;
589         return 0;
590 }
591
592
593 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
594 {
595         ePtr<eDVBAllocatedDemux> demux;
596
597         if (m_cached_channel && m_releaseCachedChannelTimer.isActive())
598         {
599                 m_cached_channel_state_changed_conn.disconnect();
600                 m_cached_channel=0;
601                 m_releaseCachedChannelTimer.stop();
602         }
603
604         eDVBChannel *ch;
605         ch = new eDVBChannel(this, 0);
606
607         channel = ch;
608         return 0;
609 }
610
611 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
612 {
613         m_active_channels.push_back(active_channel(chid, ch));
614         /* emit */ m_channelAdded(ch);
615         return 0;
616 }
617
618 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
619 {
620         int cnt = 0;
621         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
622         {
623                 if (i->m_channel == ch)
624                 {
625                         i = m_active_channels.erase(i);
626                         ++cnt;
627                 } else
628                         ++i;
629         }
630         ASSERT(cnt == 1);
631         if (cnt == 1)
632                 return 0;
633         return -ENOENT;
634 }
635
636 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
637 {
638         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
639         return 0;
640 }
641
642 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm)
643 {
644         ePtr<eDVBRegisteredFrontend> best;
645         int bestval = 0;
646
647         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
648                 if (!i->m_inuse)
649                 {
650                         int c = i->m_frontend->isCompatibleWith(feparm);
651                         if (c > bestval)
652                                 bestval = c;
653                 }
654         return bestval;
655 }
656
657 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
658 {
659         if (channellist)
660         {
661                 ePtr<iDVBFrontendParameters> feparm;
662                 if (!channellist->getChannelFrontendData(chid, feparm))
663                 {
664                         int system;
665                         if (!feparm->getSystem(system))
666                         {
667                                 switch(system)
668                                 {
669                                         case iDVBFrontend::feSatellite:
670                                                 return 50000;
671                                         case iDVBFrontend::feCable:
672                                                 return 40000;
673                                         case iDVBFrontend::feTerrestrial:
674                                                 return 30000;
675                                         default:
676                                                 break;
677                                 }
678                         }
679                 }
680         }
681         return 0;
682 }
683
684 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
685 {
686         int ret=0;
687         if (m_cached_channel)
688         {
689                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
690                 if(channelid==cache_chan->getChannelID())
691                         return tuner_type_channel_default(m_list, channelid);
692         }
693
694                 /* first, check if a channel is already existing. */
695 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
696         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
697         {
698 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
699                 if (i->m_channel_id == channelid)
700                 {
701 //                      eDebug("found shared channel..");
702                         return tuner_type_channel_default(m_list, channelid);
703                 }
704         }
705
706         int *decremented_cached_channel_fe_usecount=NULL,
707                 *decremented_fe_usecount=NULL;
708
709         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
710         {
711 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
712                 if (i->m_channel_id == ignore)
713                 {
714                         eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
715                         // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
716                         // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
717                         // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
718                         // or 2 when the cached channel is not equal to the compared channel
719                         if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2)  // channel only used once..
720                         {
721                                 ePtr<iDVBFrontend> fe;
722                                 if (!i->m_channel->getFrontend(fe))
723                                 {
724                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
725                                         {
726                                                 if ( &(*fe) == &(*ii->m_frontend) )
727                                                 {
728                                                         --ii->m_inuse;
729                                                         decremented_fe_usecount = &ii->m_inuse;
730                                                         if (channel == &(*m_cached_channel))
731                                                                 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
732                                                         break;
733                                                 }
734                                         }
735                                 }
736                         }
737                         break;
738                 }
739         }
740
741         if (!decremented_cached_channel_fe_usecount)
742         {
743                 if (m_cached_channel)
744                 {
745                         eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
746                         if (channel->getUseCount() == 1)
747                         {
748                                 ePtr<iDVBFrontend> fe;
749                                 if (!channel->getFrontend(fe))
750                                 {
751                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
752                                         {
753                                                 if ( &(*fe) == &(*ii->m_frontend) )
754                                                 {
755                                                         --ii->m_inuse;
756                                                         decremented_cached_channel_fe_usecount = &ii->m_inuse;
757                                                         break;
758                                                 }
759                                         }
760                                 }
761                         }
762                 }
763         }
764         else
765                 decremented_cached_channel_fe_usecount=NULL;
766
767         ePtr<iDVBFrontendParameters> feparm;
768
769         if (!m_list)
770         {
771                 eDebug("no channel list set!");
772                 goto error;
773         }
774
775         if (m_list->getChannelFrontendData(channelid, feparm))
776         {
777                 eDebug("channel not found!");
778                 goto error;
779         }
780
781         ret = canAllocateFrontend(feparm);
782
783 error:
784         if (decremented_fe_usecount)
785                 ++(*decremented_fe_usecount);
786         if (decremented_cached_channel_fe_usecount)
787                 ++(*decremented_cached_channel_fe_usecount);
788
789         return ret;
790 }
791
792 bool eDVBResourceManager::canMeasureFrontendInputPower()
793 {
794         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
795         {
796                 return i->m_frontend->readInputpower() >= 0;
797         }
798         return false;
799 }
800
801 class eDVBChannelFilePush: public eFilePushThread
802 {
803 public:
804         eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
805         void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
806
807                         /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
808                         /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
809         void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
810 protected:
811         int m_iframe_search, m_iframe_state, m_pid;
812         int m_timebase_change;
813         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
814 };
815
816 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t &current_span_remaining)
817 {
818 #if 0
819         if (m_timebase_change)
820         {
821                 eDebug("timebase change: %d", m_timebase_change);
822                 int offset;
823                 for (offset = 0; offset < len; offset += 188)
824                 {
825                         unsigned char *pkt = (unsigned char*)_data + offset;
826                         if (pkt[1] & 0x40) /* pusi */
827                         {
828                                 if (pkt[3] & 0x20) // adaption field present?
829                                         pkt += pkt[4] + 4 + 1;  /* skip adaption field and header */
830                                 else
831                                         pkt += 4; /* skip header */
832                                 if (pkt[0] || pkt[1] || (pkt[2] != 1))
833                                 {
834                                         eWarning("broken startcode");
835                                         continue;
836                                 }
837
838                                 pts_t pts = 0;
839
840                                 if (pkt[7] & 0x80) // PTS present?
841                                 {
842                                         pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
843                                         pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
844                                         pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
845                                         pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
846                                         pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
847
848 #if 0
849                                         off_t off = 0;
850                                         RESULT r = m_tstools.fixupPTS(off, pts);
851                                         if (r)
852                                                 eWarning("fixup PTS while trickmode playback failed.\n");
853 #endif
854
855                                         int sec = pts / 90000;
856                                         int frm = pts % 90000;
857                                         int min = sec / 60;
858                                         sec %= 60;
859                                         int hr = min / 60;
860                                         min %= 60;
861                                         int d = hr / 24;
862                                         hr %= 24;
863
864 //                                      eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
865
866                                         pts += 0x80000000LL;
867                                         pts *= m_timebase_change;
868                                         pts >>= 16;
869
870                                         sec = pts / 90000;
871                                         frm = pts % 90000;
872                                         min = sec / 60;
873                                         sec %= 60;
874                                         hr = min / 60;
875                                         min %= 60;
876                                         d = hr / 24;
877                                         hr %= 24;
878
879 //                                      eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
880
881                                         pkt[9] &= ~0xE;
882                                         pkt[10] = 0;
883                                         pkt[11] &= ~1;
884                                         pkt[12] = 0;
885                                         pkt[13] &= ~1;
886
887                                         pkt[9]  |= (pts >> 29) & 0xE;
888                                         pkt[10] |= (pts >> 22) & 0xFF;
889                                         pkt[11] |= (pts >> 14) & 0xFE;
890                                         pkt[12] |= (pts >> 7) & 0xFF;
891                                         pkt[13] |= (pts << 1) & 0xFE;
892                                 }
893                         }
894                 }
895         }
896 #endif
897
898 #if 1 /* not yet */
899         if (!m_iframe_search)
900                 return len;
901
902         unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
903
904 //      eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
905
906         unsigned char *d = data;
907         while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
908         {
909                 int offset = d - data;
910                 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
911                 unsigned char *ts = data + ts_offset;
912                 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
913
914                 if ((d[3] == 0) && (m_pid == pid))  /* picture start */
915                 {
916                         int picture_type = (d[5] >> 3) & 7;
917                         d += 4;
918
919 //                      eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
920
921                         if (m_iframe_state == 1)
922                         {
923                                         /* we are allowing data, and stop allowing data on the next frame. 
924                                            we now found a frame. so stop here. */
925                                 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
926                                 current_span_remaining = 0;
927                                 m_iframe_state = 0;
928                                 unsigned char *fts = ts + 188;
929                                 while (fts < (data + len))
930                                 {
931                                         fts[1] |= 0x1f;
932                                         fts[2] |= 0xff; /* drop packet */
933                                         fts += 188;
934                                 }
935
936                                 return len; // ts_offset + 188; /* deliver this packet, but not more. */
937                         } else
938                         {
939                                 if (picture_type != 1) /* we are only interested in I frames */
940                                         continue;
941
942                                 unsigned char *fts = data;
943                                 while (fts < ts)
944                                 {
945                                         fts[1] |= 0x1f;
946                                         fts[2] |= 0xff; /* drop packet */
947
948                                         fts += 188;
949                                 }
950                                                 /* force payload only */
951                                 ts[3] &= ~0x30;
952                                 ts[3] |=  0x10;
953
954 //                              memset(ts + 4, 0xFF, (offset % 188) - 4);
955
956                                 m_iframe_state = 1;
957                         }
958                 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
959                 {
960                         if (m_pid != pid)
961                         {
962                                 eDebug("now locked to pid %04x", pid);
963                                 m_pid = pid;
964                         }
965 //                      m_pid = 0x6e;
966                         d += 4;
967                 } else
968                         d += 4; /* ignore */
969
970         }
971
972         if (m_iframe_state == 1)
973                 return len;
974         else
975                 return 0; /* we need find an iframe first */
976 #else
977         return len;
978 #endif
979 }
980
981 DEFINE_REF(eDVBChannel);
982
983 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
984 {
985         m_frontend = frontend;
986
987         m_pvr_thread = 0;
988         
989         m_skipmode_n = m_skipmode_m = 0;
990         
991         if (m_frontend)
992                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
993 }
994
995 eDVBChannel::~eDVBChannel()
996 {
997         if (m_channel_id)
998                 m_mgr->removeChannel(this);
999
1000         stopFile();
1001 }
1002
1003 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1004 {
1005         int state, ourstate = 0;
1006         
1007                 /* if we are already in shutdown, don't change state. */
1008         if (m_state == state_release)
1009                 return;
1010         
1011         if (fe->getState(state))
1012                 return;
1013         
1014         if (state == iDVBFrontend::stateLock)
1015         {
1016                 eDebug("OURSTATE: ok");
1017                 ourstate = state_ok;
1018         } else if (state == iDVBFrontend::stateTuning)
1019         {
1020                 eDebug("OURSTATE: tuning");
1021                 ourstate = state_tuning;
1022         } else if (state == iDVBFrontend::stateLostLock)
1023         {
1024                         /* on managed channels, we try to retune in order to re-acquire lock. */
1025                 if (m_current_frontend_parameters)
1026                 {
1027                         eDebug("OURSTATE: lost lock, trying to retune");
1028                         ourstate = state_tuning;
1029                         m_frontend->get().tune(*m_current_frontend_parameters);
1030                 } else
1031                         /* on unmanaged channels, we don't do this. the client will do this. */
1032                 {
1033                         eDebug("OURSTATE: lost lock, unavailable now.");
1034                         ourstate = state_unavailable;
1035                 }
1036         } else if (state == iDVBFrontend::stateFailed)
1037         {
1038                 eDebug("OURSTATE: failed");
1039                 ourstate = state_failed;
1040         } else
1041                 eFatal("state unknown");
1042         
1043         if (ourstate != m_state)
1044         {
1045                 m_state = ourstate;
1046                 m_stateChanged(this);
1047         }
1048 }
1049
1050 void eDVBChannel::pvrEvent(int event)
1051 {
1052         switch (event)
1053         {
1054         case eFilePushThread::evtEOF:
1055                 eDebug("eDVBChannel: End of file!");
1056                 m_event(this, evtEOF);
1057                 break;
1058         case eFilePushThread::evtUser: /* start */
1059                 eDebug("SOF");
1060                 m_event(this, evtSOF);
1061                 break;
1062         }
1063 }
1064
1065 void eDVBChannel::cueSheetEvent(int event)
1066 {
1067                 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1068         if (!m_pvr_thread)
1069                 return;
1070         switch (event)
1071         {
1072         case eCueSheet::evtSeek:
1073                 eDebug("seek.");
1074                 flushPVR(m_cue->m_decoding_demux);
1075                 break;
1076         case eCueSheet::evtSkipmode:
1077         {
1078                 {
1079                         m_cue->m_lock.WrLock();
1080                         m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1081                         m_cue->m_lock.Unlock();
1082                         eRdLocker l(m_cue->m_lock);
1083                         if (m_cue->m_skipmode_ratio)
1084                         {
1085                                 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1086                                 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1087                                                 /* i agree that this might look a bit like black magic. */
1088                                 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1089                                 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1090
1091                                 if (m_cue->m_skipmode_ratio < 0)
1092                                         m_skipmode_m -= m_skipmode_n;
1093
1094                                 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1095
1096                                 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1097                                 {
1098                                         eWarning("something is wrong with this calculation");
1099                                         m_skipmode_n = m_skipmode_m = 0;
1100                                 }
1101                         } else
1102                         {
1103                                 eDebug("skipmode ratio is 0, normal play");
1104                                 m_skipmode_n = m_skipmode_m = 0;
1105                         }
1106                 }
1107                 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1108                 if (m_cue->m_skipmode_ratio != 0)
1109                         m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1110                 else
1111                         m_pvr_thread->setTimebaseChange(0); /* normal playback */
1112                 eDebug("flush pvr");
1113                 flushPVR(m_cue->m_decoding_demux);
1114                 eDebug("done");
1115                 break;
1116         }
1117         case eCueSheet::evtSpanChanged:
1118         {
1119                 m_source_span.clear();
1120                 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1121                 {
1122                         off_t offset_in, offset_out;
1123                         pts_t pts_in = i->first, pts_out = i->second;
1124                         if (m_tstools.getOffset(offset_in, pts_in) || m_tstools.getOffset(offset_out, pts_out))
1125                         {
1126                                 eDebug("span translation failed.\n");
1127                                 continue;
1128                         }
1129                         eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1130                         m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1131                 }
1132                 break;
1133         }
1134         }
1135 }
1136
1137         /* align toward zero */
1138 static inline long long align(long long x, int align)
1139 {
1140         int sign = x < 0;
1141
1142         if (sign)
1143                 x = -x;
1144
1145         x -= x % align;
1146
1147         if (sign)
1148                 x = -x;
1149
1150         return x;
1151 }
1152
1153         /* remember, this gets called from another thread. */
1154 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1155 {
1156         const int blocksize = 188;
1157         unsigned int max = align(10*1024*1024, blocksize);
1158         current_offset = align(current_offset, blocksize);
1159         
1160         if (!m_cue)
1161         {
1162                 eDebug("no cue sheet. forcing normal play");
1163                 start = current_offset;
1164                 size = max;
1165                 return;
1166         }
1167
1168         m_cue->m_lock.RdLock();
1169         if (!m_cue->m_decoding_demux)
1170         {
1171                 start = current_offset;
1172                 size = max;
1173                 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1174                 m_cue->m_lock.Unlock();
1175                 return;
1176         }
1177
1178         if (m_skipmode_n)
1179         {
1180                 eDebug("skipmode %d:%d", m_skipmode_m, m_skipmode_n);
1181                 max = align(m_skipmode_n, blocksize);
1182         }
1183
1184         eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1185
1186         current_offset += align(m_skipmode_m, blocksize);
1187
1188         while (!m_cue->m_seek_requests.empty())
1189         {
1190                 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1191                 m_cue->m_lock.Unlock();
1192                 m_cue->m_lock.WrLock();
1193                 m_cue->m_seek_requests.pop_front();
1194                 m_cue->m_lock.Unlock();
1195                 m_cue->m_lock.RdLock();
1196                 int relative = seek.first;
1197                 pts_t pts = seek.second;
1198
1199                 pts_t now = 0;
1200                 if (relative)
1201                 {
1202                         if (!m_cue->m_decoder)
1203                         {
1204                                 eDebug("no decoder - can't seek relative");
1205                                 continue;
1206                         }
1207                         if (m_cue->m_decoder->getPTS(0, now))
1208                         {
1209                                 eDebug("decoder getPTS failed, can't seek relative");
1210                                 continue;
1211                         }
1212                         if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1213                         {
1214                                 eDebug("seekTo: getCurrentPosition failed!");
1215                                 continue;
1216                         }
1217                 } else if (pts < 0) /* seek relative to end */
1218                 {
1219                         pts_t len;
1220                         if (!getLength(len))
1221                         {
1222                                 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1223                                 pts += len;
1224                         } else
1225                         {
1226                                 eWarning("getLength failed - can't seek relative to end!");
1227                                 continue;
1228                         }
1229                 }
1230                 
1231                 if (relative == 1) /* pts relative */
1232                 {
1233                         pts += now;
1234                         if (pts < 0)
1235                                 pts = 0;
1236                 }
1237
1238                 if (relative != 2)
1239                         if (pts < 0)
1240                                 pts = 0;
1241                 
1242                 if (relative == 2) /* AP relative */
1243                 {
1244                         eDebug("AP relative seeking: %lld, at %lld", pts, now);
1245                         pts_t nextap;
1246                         if (m_tstools.getNextAccessPoint(nextap, now, pts))
1247                         {
1248                                 pts = now - 90000; /* approx. 1s */
1249                                 eDebug("AP relative seeking failed!");
1250                         } else
1251                         {
1252                                 eDebug("next ap is %llx\n", pts);
1253                                 pts = nextap;
1254                         }
1255                 }
1256                 
1257                 off_t offset = 0;
1258                 if (m_tstools.getOffset(offset, pts))
1259                 {
1260                         eDebug("get offset for pts=%lld failed!", pts);
1261                         continue;
1262                 }
1263
1264                 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1265                 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1266         }
1267
1268         m_cue->m_lock.Unlock();
1269
1270         for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1271         {
1272                 long long aligned_start = align(i->first, blocksize);
1273                 long long aligned_end = align(i->second, blocksize);
1274         
1275                 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1276                 {
1277                         start = current_offset;
1278                                 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1279                         if ((aligned_end - current_offset) > max)
1280                                 size = max;
1281                         else
1282                                 size = aligned_end - current_offset;
1283                         eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1284                         return;
1285                 }
1286                 if (current_offset < aligned_start)
1287                 {
1288                                 /* ok, our current offset is in an 'out' zone. */
1289                         if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1290                         {
1291                                         /* in normal playback, just start at the next zone. */
1292                                 start = i->first;
1293
1294                                         /* size is not 64bit! */
1295                                 if ((i->second - i->first) > max)
1296                                         size = max;
1297                                 else
1298                                         size = aligned_end - aligned_start;
1299
1300                                 eDebug("skip");
1301                                 if (m_skipmode_m < 0)
1302                                 {
1303                                         eDebug("reached SOF");
1304                                                 /* reached SOF */
1305                                         m_skipmode_m = 0;
1306                                         m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1307                                 }
1308                         } else
1309                         {
1310                                         /* when skipping reverse, however, choose the zone before. */
1311                                 --i;
1312                                 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1313                                 size_t len;
1314
1315                                 aligned_start = align(i->first, blocksize);
1316                                 aligned_end = align(i->second, blocksize);
1317
1318                                 if ((aligned_end - aligned_start) > max)
1319                                         len = max;
1320                                 else
1321                                         len = aligned_end - aligned_start;
1322
1323                                 start = aligned_end - len;
1324                                 eDebug("skipping to %llx, %d", start, len);
1325                         }
1326
1327                         eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1328                         return;
1329                 }
1330         }
1331
1332         if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1333         {
1334                 eDebug("reached SOF");
1335                 m_skipmode_m = 0;
1336                 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1337         }
1338
1339         start = current_offset;
1340         size = max;
1341
1342         eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
1343         return;
1344 }
1345
1346 void eDVBChannel::AddUse()
1347 {
1348         if (++m_use_count > 1 && m_state == state_last_instance)
1349         {
1350                 m_state = state_ok;
1351                 m_stateChanged(this);
1352         }
1353 }
1354
1355 void eDVBChannel::ReleaseUse()
1356 {
1357         if (!--m_use_count)
1358         {
1359                 m_state = state_release;
1360                 m_stateChanged(this);
1361         }
1362         else if (m_use_count == 1)
1363         {
1364                 m_state = state_last_instance;
1365                 m_stateChanged(this);
1366         }
1367 }
1368
1369 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1370 {
1371         if (m_channel_id)
1372                 m_mgr->removeChannel(this);
1373                 
1374         if (!channelid)
1375                 return 0;
1376
1377         if (!m_frontend)
1378         {
1379                 eDebug("no frontend to tune!");
1380                 return -ENODEV;
1381         }
1382         
1383         m_channel_id = channelid;
1384         m_mgr->addChannel(channelid, this);
1385         m_state = state_tuning;
1386                         /* if tuning fails, shutdown the channel immediately. */
1387         int res;
1388         res = m_frontend->get().tune(*feparm);
1389         m_current_frontend_parameters = feparm;
1390         
1391         if (res)
1392         {
1393                 m_state = state_release;
1394                 m_stateChanged(this);
1395                 return res;
1396         }
1397         
1398         return 0;
1399 }
1400
1401 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1402 {
1403         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1404         return 0;
1405 }
1406
1407 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1408 {
1409         connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1410         return 0;
1411 }
1412
1413 RESULT eDVBChannel::getState(int &state)
1414 {
1415         state = m_state;
1416         return 0;
1417 }
1418
1419 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1420 {
1421         return -1;
1422 }
1423
1424 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1425 {
1426         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1427         
1428         if (!our_demux)
1429         {
1430                 demux = 0;
1431                 
1432                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1433                         return -1;
1434         }
1435         
1436         demux = *our_demux;
1437                 /* don't hold a reference to the decoding demux, we don't need it. */
1438                 
1439                 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1440                    the refcount is lost. thus, decoding demuxes are never allocated. 
1441                    
1442                    this poses a big problem for PiP. */
1443         if (cap & capDecode)
1444                 our_demux = 0;
1445         return 0;
1446 }
1447
1448 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1449 {
1450         frontend = 0;
1451         if (!m_frontend)
1452                 return -ENODEV;
1453         frontend = &m_frontend->get();
1454         if (frontend)
1455                 return 0;
1456         return -ENODEV;
1457 }
1458
1459 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &param)
1460 {
1461         param = m_current_frontend_parameters;
1462         return 0;
1463 }
1464
1465 RESULT eDVBChannel::playFile(const char *file)
1466 {
1467         ASSERT(!m_frontend);
1468         if (m_pvr_thread)
1469         {
1470                 m_pvr_thread->stop();
1471                 delete m_pvr_thread;
1472                 m_pvr_thread = 0;
1473         }
1474         
1475         m_tstools.openFile(file);
1476         
1477                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1478                    THEN DO A REAL FIX HERE! */
1479         
1480                 /* (this codepath needs to be improved anyway.) */
1481 #if HAVE_DVB_API_VERSION < 3
1482         m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1483 #else
1484         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1485 #endif
1486         if (m_pvr_fd_dst < 0)
1487         {
1488                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1489                 return -ENODEV;
1490         }
1491
1492         m_pvr_thread = new eDVBChannelFilePush();
1493         m_pvr_thread->enablePVRCommit(1);
1494         m_pvr_thread->setStreamMode(1);
1495         m_pvr_thread->setScatterGather(this);
1496
1497         if (m_pvr_thread->start(file, m_pvr_fd_dst))
1498         {
1499                 delete m_pvr_thread;
1500                 m_pvr_thread = 0;
1501                 eDebug("can't open PVR file %s (%m)", file);
1502                 return -ENOENT;
1503         }
1504         CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1505
1506         m_state = state_ok;
1507         m_stateChanged(this);
1508
1509         return 0;
1510 }
1511
1512 void eDVBChannel::stopFile()
1513 {
1514         if (m_pvr_thread)
1515         {
1516                 m_pvr_thread->stop();
1517                 ::close(m_pvr_fd_dst);
1518                 delete m_pvr_thread;
1519                 m_pvr_thread = 0;
1520         }
1521 }
1522
1523 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1524 {
1525         m_conn_cueSheetEvent = 0;
1526         m_cue = cuesheet;
1527         if (m_cue)
1528                 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1529 }
1530
1531 RESULT eDVBChannel::getLength(pts_t &len)
1532 {
1533         return m_tstools.calcLen(len);
1534 }
1535
1536 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1537 {
1538         if (!decoding_demux)
1539                 return -1;
1540         
1541         pts_t now;
1542         
1543         int r;
1544         
1545         if (mode == 0) /* demux */
1546         {
1547                 r = decoding_demux->getSTC(now, 0);
1548                 if (r)
1549                 {
1550                         eDebug("demux getSTC failed");
1551                         return -1;
1552                 }
1553         } else
1554                 now = pos; /* fixup supplied */
1555         
1556         off_t off = 0; /* TODO: fixme */
1557         r = m_tstools.fixupPTS(off, now);
1558         if (r)
1559         {
1560                 eDebug("fixup PTS failed");
1561                 return -1;
1562         }
1563         
1564         pos = now;
1565         
1566         return 0;
1567 }
1568
1569 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1570 {
1571                         /* when seeking, we have to ensure that all buffers are flushed.
1572                            there are basically 3 buffers:
1573                            a.) the filepush's internal buffer
1574                            b.) the PVR buffer (before demux)
1575                            c.) the ratebuffer (after demux)
1576                            
1577                            it's important to clear them in the correct order, otherwise
1578                            the ratebuffer (for example) would immediately refill from
1579                            the not-yet-flushed PVR buffer.
1580                         */
1581
1582         m_pvr_thread->pause();
1583                 /* flush internal filepush buffer */
1584         m_pvr_thread->flush();
1585                 /* HACK: flush PVR buffer */
1586         ::ioctl(m_pvr_fd_dst, 0);
1587         
1588                 /* flush ratebuffers (video, audio) */
1589         if (decoding_demux)
1590                 decoding_demux->flush();
1591
1592                 /* demux will also flush all decoder.. */
1593                 /* resume will re-query the SG */
1594         m_pvr_thread->resume();
1595 }
1596
1597 DEFINE_REF(eCueSheet);
1598
1599 eCueSheet::eCueSheet()
1600 {
1601         m_skipmode_ratio = 0;
1602 }
1603
1604 void eCueSheet::seekTo(int relative, const pts_t &pts)
1605 {
1606         m_lock.WrLock();
1607         m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1608         m_lock.Unlock();
1609         m_event(evtSeek);
1610 }
1611         
1612 void eCueSheet::clear()
1613 {
1614         m_lock.WrLock();
1615         m_spans.clear();
1616         m_lock.Unlock();
1617 }
1618
1619 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1620 {
1621         assert(begin < end);
1622         m_lock.WrLock();
1623         m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1624         m_lock.Unlock();
1625 }
1626
1627 void eCueSheet::commitSpans()
1628 {
1629         m_event(evtSpanChanged);
1630 }
1631
1632 void eCueSheet::setSkipmode(const pts_t &ratio)
1633 {
1634         m_lock.WrLock();
1635         m_skipmode_ratio = ratio;
1636         m_lock.Unlock();
1637         m_event(evtSkipmode);
1638 }
1639
1640 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1641 {
1642         m_decoding_demux = demux;
1643         m_decoder = decoder;
1644 }
1645
1646 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1647 {
1648         connection = new eConnection(this, m_event.connect(event));
1649         return 0;
1650 }