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