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