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