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