write leaveTransponder message to camd.socket
[enigma2.git] / lib / dvb / dvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/filepush.h>
3 #include <lib/dvb/idvb.h>
4 #include <lib/dvb/dvb.h>
5 #include <lib/dvb/pmt.h>
6 #include <lib/dvb/sec.h>
7
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14
15 DEFINE_REF(eDVBRegisteredFrontend);
16 DEFINE_REF(eDVBRegisteredDemux);
17
18 DEFINE_REF(eDVBAllocatedFrontend);
19
20 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
21 {
22         m_fe->inc_use();
23 }
24
25 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
26 {
27         m_fe->dec_use();
28 }
29
30 DEFINE_REF(eDVBAllocatedDemux);
31
32 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
33 {
34         m_demux->m_inuse++;
35 }
36
37 eDVBAllocatedDemux::~eDVBAllocatedDemux()
38 {
39         --m_demux->m_inuse;
40 }
41
42 DEFINE_REF(eDVBResourceManager);
43
44 eDVBResourceManager *eDVBResourceManager::instance;
45
46 RESULT eDVBResourceManager::getInstance(ePtr<eDVBResourceManager> &ptr)
47 {
48         if (instance)
49         {
50                 ptr = instance;
51                 return 0;
52         }
53         return -1;
54 }
55
56 ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
57 {
58         ePtr<eDVBResourceManager> ptr;
59         eDVBResourceManager::getInstance(ptr);
60         return ptr;
61 }
62
63 eDVBResourceManager::eDVBResourceManager()
64         :m_releaseCachedChannelTimer(eApp)
65 {
66         avail = 1;
67         busy = 0;
68         m_sec = new eDVBSatelliteEquipmentControl(m_frontend);
69         if (!instance)
70                 instance = this;
71                 
72                 /* search available adapters... */
73
74                 // add linux devices
75         
76         int num_adapter = 0;
77         while (eDVBAdapterLinux::exist(num_adapter))
78         {
79                 addAdapter(new eDVBAdapterLinux(num_adapter));
80                 num_adapter++;
81         }
82         
83         eDebug("found %d adapter, %d frontends and %d demux", 
84                 m_adapter.size(), m_frontend.size(), m_demux.size());
85
86         eDVBCAService::registerChannelCallback(this);
87
88         CONNECT(m_releaseCachedChannelTimer.timeout, eDVBResourceManager::releaseCachedChannel);
89 }
90
91 void eDVBResourceManager::feStateChanged()
92 {
93         int mask=0;
94         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
95                 if (i->m_inuse)
96                         mask |= ( 1 << i->m_frontend->getSlotID() );
97         /* emit */ frontendUseMaskChanged(mask);
98 }
99
100 DEFINE_REF(eDVBAdapterLinux);
101 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
102 {
103                 // scan frontends
104         int num_fe = 0;
105         
106         eDebug("scanning for frontends..");
107         while (1)
108         {
109                 struct stat s;
110                 char filename[128];
111 #if HAVE_DVB_API_VERSION < 3
112                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
113 #else
114                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
115 #endif
116                 if (stat(filename, &s))
117                         break;
118                 ePtr<eDVBFrontend> fe;
119
120                 int ok = 0;
121                 fe = new eDVBFrontend(m_nr, num_fe, ok);
122                 if (ok)
123                         m_frontend.push_back(fe);
124                 ++num_fe;
125         }
126         
127                 // scan demux
128         int num_demux = 0;
129         while (1)
130         {
131                 struct stat s;
132                 char filename[128];
133 #if HAVE_DVB_API_VERSION < 3
134                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
135 #else
136                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
137 #endif
138                 if (stat(filename, &s))
139                         break;
140                 ePtr<eDVBDemux> demux;
141                 
142                 demux = new eDVBDemux(m_nr, num_demux);
143                 m_demux.push_back(demux);
144                         
145                 ++num_demux;
146         }
147 }
148
149 int eDVBAdapterLinux::getNumDemux()
150 {
151         return m_demux.size();
152 }
153
154 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
155 {
156         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
157         while (nr && (i != m_demux.end()))
158         {
159                 --nr;
160                 ++i;
161         }
162         
163         if (i != m_demux.end())
164                 demux = *i;
165         else
166                 return -1;
167                 
168         return 0;
169 }
170
171 int eDVBAdapterLinux::getNumFrontends()
172 {
173         return m_frontend.size();
174 }
175
176 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
177 {
178         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
179         while (nr && (i != m_frontend.end()))
180         {
181                 --nr;
182                 ++i;
183         }
184         
185         if (i != m_frontend.end())
186                 fe = *i;
187         else
188                 return -1;
189                 
190         return 0;
191 }
192
193 int eDVBAdapterLinux::exist(int nr)
194 {
195         struct stat s;
196         char filename[128];
197 #if HAVE_DVB_API_VERSION < 3
198         sprintf(filename, "/dev/dvb/card%d", nr);
199 #else
200         sprintf(filename, "/dev/dvb/adapter%d", nr);
201 #endif
202         if (!stat(filename, &s))
203                 return 1;
204         return 0;
205 }
206
207 eDVBResourceManager::~eDVBResourceManager()
208 {
209         if (instance == this)
210                 instance = 0;
211 }
212
213 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
214 {
215         int num_fe = adapter->getNumFrontends();
216         int num_demux = adapter->getNumDemux();
217         
218         m_adapter.push_back(adapter);
219         
220         int i;
221         for (i=0; i<num_demux; ++i)
222         {
223                 ePtr<eDVBDemux> demux;
224                 if (!adapter->getDemux(demux, i))
225                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
226         }
227
228         ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
229         for (i=0; i<num_fe; ++i)
230         {
231                 ePtr<eDVBFrontend> frontend;
232                 if (!adapter->getFrontend(frontend, i))
233                 {
234                         int frontendType=0;
235                         frontend->getFrontendType(frontendType);
236                         eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
237                         CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
238                         m_frontend.push_back(new_fe);
239                         frontend->setSEC(m_sec);
240                         // we must link all dvb-t frontends ( for active antenna voltage )
241                         if (frontendType == iDVBFrontend::feTerrestrial)
242                         {
243                                 if (prev_dvbt_frontend)
244                                 {
245                                         prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (int)new_fe);
246                                         frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (int)&(*prev_dvbt_frontend));
247                                 }
248                                 prev_dvbt_frontend = new_fe;
249                         }
250                 }
251         }
252 }
253
254 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
255 {
256         if (!PyList_Check(list))
257         {
258                 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
259                 return NULL;
260         }
261         if ((unsigned int)PyList_Size(list) != m_frontend.size())
262         {
263                 char blasel[256];
264                 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
265                         m_frontend.size(), PyList_Size(list));
266                 PyErr_SetString(PyExc_StandardError, blasel);
267                 return NULL;
268         }
269         int pos=0;
270         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
271         {
272                 ePyObject obj = PyList_GET_ITEM(list, pos++);
273                 if (!i->m_frontend->setSlotInfo(obj))
274                         return NULL;
275         }
276         Py_RETURN_NONE;
277 }
278
279 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm)
280 {
281         ePtr<eDVBRegisteredFrontend> best;
282         int bestval = 0;
283
284         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
285                 if (!i->m_inuse)
286                 {
287                         int c = i->m_frontend->isCompatibleWith(feparm);
288                         if (c > bestval)
289                         {
290                                 bestval = c;
291                                 best = i;
292                         }
293                 }
294
295         if (best)
296         {
297                 fe = new eDVBAllocatedFrontend(best);
298                 return 0;
299         }
300         
301         fe = 0;
302         
303         return -1;
304 }
305
306 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
307 {
308         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
309                 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
310                 {
311                         // check if another slot linked to this is in use
312                         eDVBRegisteredFrontend *satpos_depends_to_fe =
313                                 (eDVBRegisteredFrontend*) i->m_frontend->m_data[eDVBFrontend::SATPOS_DEPENDS_PTR];
314                         if ( (int)satpos_depends_to_fe != -1 )
315                         {
316                                 if (satpos_depends_to_fe->m_inuse)
317                                 {
318                                         eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
319                                         goto alloc_fe_by_id_not_possible;
320                                 }
321                         }
322                         else // check linked tuners
323                         {
324                                 eDVBRegisteredFrontend *next =
325                                         (eDVBRegisteredFrontend *) i->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR];
326                                 while ( (int)next != -1 )
327                                 {
328                                         if (next->m_inuse)
329                                         {
330                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
331                                                 goto alloc_fe_by_id_not_possible;
332                                         }
333                                         next = (eDVBRegisteredFrontend *)next->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR];
334                                 }
335                                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)
336                                         i->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR];
337                                 while ( (int)prev != -1 )
338                                 {
339                                         if (prev->m_inuse)
340                                         {
341                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
342                                                 goto alloc_fe_by_id_not_possible;
343                                         }
344                                         prev = (eDVBRegisteredFrontend *)prev->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR];
345                                 }
346                         }
347                         fe = new eDVBAllocatedFrontend(i);
348                         return 0;
349                 }
350 alloc_fe_by_id_not_possible:
351         fe = 0;
352         return -1;
353 }
354
355 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
356 {
357                 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
358                    never use the first one unless we need a decoding demux. */
359
360         eDebug("allocate demux");
361         eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
362         
363         if (i == m_demux.end())
364                 return -1;
365                 
366         int n=0;
367                 /* FIXME: hardware demux policy */
368         if (!(cap & iDVBChannel::capDecode))
369         {
370                 if (m_demux.size() > 2)  /* assumed to be true, otherwise we have lost anyway */
371                 {
372                         ++i, ++n;
373                         ++i, ++n;
374                 }
375         }
376         
377         for (; i != m_demux.end(); ++i, ++n)
378         {
379                 int is_decode = n < 2;
380                 
381                 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
382                 
383                 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
384                 {
385                         if ((cap & iDVBChannel::capDecode) && !is_decode)
386                                 continue;
387                         
388                         demux = new eDVBAllocatedDemux(i);
389                         if (fe)
390                                 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
391                         else
392                                 demux->get().setSourcePVR(0);
393                         return 0;
394                 }
395         }
396         eDebug("demux not found");
397         return -1;
398 }
399
400 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
401 {
402         m_list = list;
403         return 0;
404 }
405
406 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
407 {
408         list = m_list;
409         if (list)
410                 return 0;
411         else
412                 return -ENOENT;
413 }
414
415 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
416 {
417                 /* first, check if a channel is already existing. */
418
419         if (m_cached_channel)
420         {
421                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
422                 if(channelid==cache_chan->getChannelID())
423                 {
424                         eDebug("use cached_channel");
425                         channel = m_cached_channel;
426                         return 0;
427                 }
428                 m_cached_channel_state_changed_conn.disconnect();
429                 m_cached_channel=0;
430                 m_releaseCachedChannelTimer.stop();
431         }
432
433 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
434         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
435         {
436 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
437                 if (i->m_channel_id == channelid)
438                 {
439 //                      eDebug("found shared channel..");
440                         channel = i->m_channel;
441                         return 0;
442                 }
443         }
444         
445         /* no currently available channel is tuned to this channelid. create a new one, if possible. */
446
447         if (!m_list)
448         {
449                 eDebug("no channel list set!");
450                 return -ENOENT;
451         }
452
453         ePtr<iDVBFrontendParameters> feparm;
454         if (m_list->getChannelFrontendData(channelid, feparm))
455         {
456                 eDebug("channel not found!");
457                 return -ENOENT;
458         }
459
460         /* allocate a frontend. */
461         
462         ePtr<eDVBAllocatedFrontend> fe;
463         
464         if (allocateFrontend(fe, feparm))
465                 return errNoFrontend;
466
467         RESULT res;
468         ePtr<eDVBChannel> ch;
469         ch = new eDVBChannel(this, fe);
470
471         res = ch->setChannel(channelid, feparm);
472         if (res)
473         {
474                 channel = 0;
475                 return errChidNotFound;
476         }
477         m_cached_channel = channel = ch;
478         m_cached_channel_state_changed_conn =
479                 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
480
481         return 0;
482 }
483
484 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
485 {
486         int state=0;
487         chan->getState(state);
488         switch (state)
489         {
490                 case iDVBChannel::state_release:
491                 case iDVBChannel::state_ok:
492                 {
493                         eDebug("stop release channel timer");
494                         m_releaseCachedChannelTimer.stop();
495                         break;
496                 }
497                 case iDVBChannel::state_last_instance:
498                 {
499                         eDebug("start release channel timer");
500                         m_releaseCachedChannelTimer.start(3000, true);
501                         break;
502                 }
503                 default: // ignore all other events
504                         break;
505         }
506 }
507
508 void eDVBResourceManager::releaseCachedChannel()
509 {
510         eDebug("release cached channel (timer timeout)");
511         m_cached_channel=0;
512 }
513
514 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
515 {
516         ePtr<eDVBAllocatedFrontend> fe;
517
518         if (m_cached_channel)
519         {
520                 m_cached_channel_state_changed_conn.disconnect();
521                 m_cached_channel=0;
522                 m_releaseCachedChannelTimer.stop();
523         }
524
525         if (allocateFrontendByIndex(fe, slot_index))
526                 return errNoFrontend;
527         
528         eDVBChannel *ch;
529         ch = new eDVBChannel(this, fe);
530
531         channel = ch;
532         return 0;
533 }
534
535
536 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
537 {
538         ePtr<eDVBAllocatedDemux> demux;
539
540         if (m_cached_channel && m_releaseCachedChannelTimer.isActive())
541         {
542                 m_cached_channel_state_changed_conn.disconnect();
543                 m_cached_channel=0;
544                 m_releaseCachedChannelTimer.stop();
545         }
546
547         eDVBChannel *ch;
548         ch = new eDVBChannel(this, 0);
549
550         channel = ch;
551         return 0;
552 }
553
554 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
555 {
556         m_active_channels.push_back(active_channel(chid, ch));
557         /* emit */ m_channelAdded(ch);
558         return 0;
559 }
560
561 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
562 {
563         int cnt = 0;
564         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
565         {
566                 if (i->m_channel == ch)
567                 {
568                         i = m_active_channels.erase(i);
569                         ++cnt;
570                 } else
571                         ++i;
572         }
573         ASSERT(cnt == 1);
574         if (cnt == 1)
575                 return 0;
576         return -ENOENT;
577 }
578
579 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
580 {
581         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
582         return 0;
583 }
584
585 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm)
586 {
587         ePtr<eDVBRegisteredFrontend> best;
588         int bestval = 0;
589
590         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
591                 if (!i->m_inuse)
592                 {
593                         int c = i->m_frontend->isCompatibleWith(feparm);
594                         if (c > bestval)
595                                 bestval = c;
596                 }
597         return bestval;
598 }
599
600 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
601 {
602         int ret=30000;
603         if (m_cached_channel)
604         {
605                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
606                 if(channelid==cache_chan->getChannelID())
607                         return ret;
608         }
609
610                 /* first, check if a channel is already existing. */
611 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
612         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
613         {
614 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
615                 if (i->m_channel_id == channelid)
616                 {
617 //                      eDebug("found shared channel..");
618                         return ret;
619                 }
620         }
621
622         int *decremented_cached_channel_fe_usecount=NULL,
623                 *decremented_fe_usecount=NULL;
624
625         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
626         {
627 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
628                 if (i->m_channel_id == ignore)
629                 {
630                         eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
631                         // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
632                         // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
633                         // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
634                         // or 2 when the cached channel is not equal to the compared channel
635                         if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2)  // channel only used once..
636                         {
637                                 ePtr<iDVBFrontend> fe;
638                                 if (!i->m_channel->getFrontend(fe))
639                                 {
640                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
641                                         {
642                                                 if ( &(*fe) == &(*ii->m_frontend) )
643                                                 {
644                                                         --ii->m_inuse;
645                                                         decremented_fe_usecount = &ii->m_inuse;
646                                                         if (channel == &(*m_cached_channel))
647                                                                 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
648                                                         break;
649                                                 }
650                                         }
651                                 }
652                         }
653                         break;
654                 }
655         }
656
657         if (!decremented_cached_channel_fe_usecount)
658         {
659                 if (m_cached_channel)
660                 {
661                         eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
662                         if (channel->getUseCount() == 1)
663                         {
664                                 ePtr<iDVBFrontend> fe;
665                                 if (!channel->getFrontend(fe))
666                                 {
667                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
668                                         {
669                                                 if ( &(*fe) == &(*ii->m_frontend) )
670                                                 {
671                                                         --ii->m_inuse;
672                                                         decremented_cached_channel_fe_usecount = &ii->m_inuse;
673                                                         break;
674                                                 }
675                                         }
676                                 }
677                         }
678                 }
679         }
680         else
681                 decremented_cached_channel_fe_usecount=NULL;
682
683         ePtr<iDVBFrontendParameters> feparm;
684
685         if (!m_list)
686         {
687                 eDebug("no channel list set!");
688                 ret = 0;
689                 goto error;
690         }
691
692         if (m_list->getChannelFrontendData(channelid, feparm))
693         {
694                 eDebug("channel not found!");
695                 ret = 0;
696                 goto error;
697         }
698
699         ret = canAllocateFrontend(feparm);
700
701 error:
702         if (decremented_fe_usecount)
703                 ++(*decremented_fe_usecount);
704         if (decremented_cached_channel_fe_usecount)
705                 ++(*decremented_cached_channel_fe_usecount);
706
707         return ret;
708 }
709
710 class eDVBChannelFilePush: public eFilePushThread
711 {
712 public:
713         void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
714 protected:
715         int m_iframe_search, m_iframe_state, m_pid;
716         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
717 };
718
719 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t &current_span_remaining)
720 {
721 #if 0 /* not yet */
722         if (!m_iframe_search)
723                 return len;
724
725         unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
726
727         eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
728
729         unsigned char *d = data;
730         while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
731         {
732                 int offset = d - data;
733                 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
734                 unsigned char *ts = data + ts_offset;
735                 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
736
737                 if ((d[3] == 0) && (m_pid == pid))  /* picture start */
738                 {
739                         int picture_type = (d[5] >> 3) & 7;
740                         d += 4;
741                         
742                         eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
743
744                         if (m_iframe_state == 1)
745                         {
746                                         /* we are allowing data, and stop allowing data on the next frame. 
747                                            we now found a frame. so stop here. */
748                                 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
749                                 current_span_remaining = 0;
750                                 m_iframe_state = 0;
751                                 unsigned char *fts = ts + 188;
752                                 while (fts < (data + len))
753                                 {
754                                         fts[1] |= 0x1f;
755                                         fts[2] |= 0xff; /* drop packet */
756                                         fts += 188;
757                                 }
758
759                                 return len; // ts_offset + 188; /* deliver this packet, but not more. */
760                         } else
761                         {
762                                 if (picture_type != 1) /* we are only interested in I frames */
763                                         continue;
764                         
765                                 unsigned char *fts = data;
766                                 while (fts < ts)
767                                 {
768                                         fts[1] |= 0x1f;
769                                         fts[2] |= 0xff; /* drop packet */
770                                 
771                                         fts += 188;
772                                 }
773                                                 /* force payload only */
774                                 ts[3] &= ~0x30;
775                                 ts[3] |=  0x10;
776                                 
777 //                              memset(ts + 4, 0xFF, (offset % 188) - 4);
778
779                                 m_iframe_state = 1;
780                         }
781                 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
782                 {
783                         if (m_pid != pid)
784                         {
785                                 eDebug("now locked to pid %04x", pid);
786                                 m_pid = pid;
787                         }
788 //                      m_pid = 0x6e;
789                         d += 4;
790                 } else
791                         d += 4; /* ignore */
792
793         }
794
795         if (m_iframe_state == 1)
796                 return len;
797         else
798                 return 0; /* we need find an iframe first */
799 #else
800         return len;
801 #endif
802 }
803
804 DEFINE_REF(eDVBChannel);
805
806 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
807 {
808         m_frontend = frontend;
809
810         m_pvr_thread = 0;
811         
812         m_skipmode_n = m_skipmode_m = 0;
813         
814         if (m_frontend)
815                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
816 }
817
818 eDVBChannel::~eDVBChannel()
819 {
820         if (m_channel_id)
821                 m_mgr->removeChannel(this);
822
823         stopFile();
824 }
825
826 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
827 {
828         int state, ourstate = 0;
829         
830                 /* if we are already in shutdown, don't change state. */
831         if (m_state == state_release)
832                 return;
833         
834         if (fe->getState(state))
835                 return;
836         
837         if (state == iDVBFrontend::stateLock)
838         {
839                 eDebug("OURSTATE: ok");
840                 ourstate = state_ok;
841         } else if (state == iDVBFrontend::stateTuning)
842         {
843                 eDebug("OURSTATE: tuning");
844                 ourstate = state_tuning;
845         } else if (state == iDVBFrontend::stateLostLock)
846         {
847                         /* on managed channels, we try to retune in order to re-acquire lock. */
848                 if (m_current_frontend_parameters)
849                 {
850                         eDebug("OURSTATE: lost lock, trying to retune");
851                         ourstate = state_tuning;
852                         m_frontend->get().tune(*m_current_frontend_parameters);
853                 } else
854                         /* on unmanaged channels, we don't do this. the client will do this. */
855                 {
856                         eDebug("OURSTATE: lost lock, unavailable now.");
857                         ourstate = state_unavailable;
858                 }
859         } else if (state == iDVBFrontend::stateFailed)
860         {
861                 eDebug("OURSTATE: failed");
862                 ourstate = state_failed;
863         } else
864                 eFatal("state unknown");
865         
866         if (ourstate != m_state)
867         {
868                 m_state = ourstate;
869                 m_stateChanged(this);
870         }
871 }
872
873 void eDVBChannel::pvrEvent(int event)
874 {
875         switch (event)
876         {
877         case eFilePushThread::evtEOF:
878                 eDebug("eDVBChannel: End of file!");
879                 m_event(this, evtEOF);
880                 break;
881         case eFilePushThread::evtUser: /* start */
882                 eDebug("SOF");
883                 m_event(this, evtSOF);
884                 break;
885         }
886 }
887
888 void eDVBChannel::cueSheetEvent(int event)
889 {
890         switch (event)
891         {
892         case eCueSheet::evtSeek:
893                 eDebug("seek.");
894                 flushPVR(m_cue->m_decoding_demux);
895                 break;
896         case eCueSheet::evtSkipmode:
897         {
898                 {
899                         m_cue->m_lock.WrLock();
900                         m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
901                         m_cue->m_lock.Unlock();
902                         eRdLocker l(m_cue->m_lock);
903                         if (m_cue->m_skipmode_ratio)
904                         {
905                                 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
906                                 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
907                                                 /* i agree that this might look a bit like black magic. */
908                                 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
909                                 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
910                                 
911                                 if (m_cue->m_skipmode_ratio < 0)
912                                         m_skipmode_m -= m_skipmode_n;
913         
914                                 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
915                                 
916                                 if (abs(m_skipmode_m) < abs(m_skipmode_n))
917                                 {
918                                         eWarning("something is wrong with this calculation");
919                                         m_skipmode_n = m_skipmode_m = 0;
920                                 }
921                                 
922                         } else
923                         {
924                                 eDebug("skipmode ratio is 0, normal play");
925                                 m_skipmode_n = m_skipmode_m = 0;
926                         }
927                 }
928                 ASSERT(m_pvr_thread);
929                 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
930                 eDebug("flush pvr");
931                 flushPVR(m_cue->m_decoding_demux);
932                 eDebug("done");
933                 break;
934         }
935         case eCueSheet::evtSpanChanged:
936         {
937                 m_source_span.clear();
938                 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
939                 {
940                         off_t offset_in, offset_out;
941                         pts_t pts_in = i->first, pts_out = i->second;
942                         if (m_tstools.getOffset(offset_in, pts_in) || m_tstools.getOffset(offset_out, pts_out))
943                         {
944                                 eDebug("span translation failed.\n");
945                                 continue;
946                         }
947                         eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
948                         m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
949                 }
950                 break;
951         }
952         }
953 }
954
955         /* align toward zero */
956 static inline long long align(long long x, int align)
957 {
958         int sign = x < 0;
959
960         if (sign)
961                 x = -x;
962
963         x -= x % align;
964
965         if (sign)
966                 x = -x;
967
968         return x;
969 }
970
971         /* remember, this gets called from another thread. */
972 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
973 {
974         const int blocksize = 188;
975         unsigned int max = align(10*1024*1024, blocksize);
976         current_offset = align(current_offset, blocksize);
977         
978         if (!m_cue)
979         {
980                 eDebug("no cue sheet. forcing normal play");
981                 start = current_offset;
982                 size = max;
983                 return;
984         }
985
986         m_cue->m_lock.RdLock();
987         if (!m_cue->m_decoding_demux)
988         {
989                 start = current_offset;
990                 size = max;
991                 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
992                 m_cue->m_lock.Unlock();
993                 return;
994         }
995
996         if (m_skipmode_n)
997         {
998                 eDebug("skipmode %d:%d", m_skipmode_m, m_skipmode_n);
999                 max = align(m_skipmode_n, blocksize);
1000         }
1001
1002         eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1003
1004         current_offset += align(m_skipmode_m, blocksize);
1005
1006         while (!m_cue->m_seek_requests.empty())
1007         {
1008                 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1009                 m_cue->m_lock.Unlock();
1010                 m_cue->m_lock.WrLock();
1011                 m_cue->m_seek_requests.pop_front();
1012                 m_cue->m_lock.Unlock();
1013                 m_cue->m_lock.RdLock();
1014                 int relative = seek.first;
1015                 pts_t pts = seek.second;
1016
1017                 pts_t now = 0;
1018                 if (relative)
1019                 {
1020                         if (!m_cue->m_decoder)
1021                         {
1022                                 eDebug("no decoder - can't seek relative");
1023                                 continue;
1024                         }
1025                         if (m_cue->m_decoder->getPTS(0, now))
1026                         {
1027                                 eDebug("decoder getPTS failed, can't seek relative");
1028                                 continue;
1029                         }
1030                         if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1031                         {
1032                                 eDebug("seekTo: getCurrentPosition failed!");
1033                                 continue;
1034                         }
1035                 } else if (pts < 0) /* seek relative to end */
1036                 {
1037                         pts_t len;
1038                         if (!getLength(len))
1039                         {
1040                                 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1041                                 pts += len;
1042                         } else
1043                         {
1044                                 eWarning("getLength failed - can't seek relative to end!");
1045                                 continue;
1046                         }
1047                 }
1048                 
1049                 if (relative == 1) /* pts relative */
1050                 {
1051                         pts += now;
1052                         if (pts < 0)
1053                                 pts = 0;
1054                 }
1055
1056                 if (relative != 2)
1057                         if (pts < 0)
1058                                 pts = 0;
1059                 
1060                 if (relative == 2) /* AP relative */
1061                 {
1062                         eDebug("AP relative seeking: %lld, at %lld", pts, now);
1063                         pts_t nextap;
1064                         if (m_tstools.getNextAccessPoint(nextap, now, pts))
1065                         {
1066                                 pts = now - 90000; /* approx. 1s */
1067                                 eDebug("AP relative seeking failed!");
1068                         } else
1069                         {
1070                                 eDebug("next ap is %llx\n", pts);
1071                                 pts = nextap;
1072                         }
1073                 }
1074                 
1075                 off_t offset = 0;
1076                 if (m_tstools.getOffset(offset, pts))
1077                 {
1078                         eDebug("get offset for pts=%lld failed!", pts);
1079                         continue;
1080                 }
1081
1082                 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1083                 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1084         }
1085
1086         m_cue->m_lock.Unlock();
1087
1088         for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1089         {
1090                 long long aligned_start = align(i->first, blocksize);
1091                 long long aligned_end = align(i->second, blocksize);
1092         
1093                 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1094                 {
1095                         start = current_offset;
1096                                 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1097                         if ((aligned_end - current_offset) > max)
1098                                 size = max;
1099                         else
1100                                 size = aligned_end - current_offset;
1101                         eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1102                         return;
1103                 }
1104                 if (current_offset < aligned_start)
1105                 {
1106                                 /* ok, our current offset is in an 'out' zone. */
1107                         if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1108                         {
1109                                         /* in normal playback, just start at the next zone. */
1110                                 start = i->first;
1111
1112                                         /* size is not 64bit! */
1113                                 if ((i->second - i->first) > max)
1114                                         size = max;
1115                                 else
1116                                         size = aligned_end - aligned_start;
1117
1118                                 eDebug("skip");
1119                                 if (m_skipmode_m < 0)
1120                                 {
1121                                         eDebug("reached SOF");
1122                                                 /* reached SOF */
1123                                         m_skipmode_m = 0;
1124                                         m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1125                                 }
1126                         } else
1127                         {
1128                                         /* when skipping reverse, however, choose the zone before. */
1129                                 --i;
1130                                 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1131                                 size_t len;
1132
1133                                 aligned_start = align(i->first, blocksize);
1134                                 aligned_end = align(i->second, blocksize);
1135
1136                                 if ((aligned_end - aligned_start) > max)
1137                                         len = max;
1138                                 else
1139                                         len = aligned_end - aligned_start;
1140
1141                                 start = aligned_end - len;
1142                                 eDebug("skipping to %llx, %d", start, len);
1143                         }
1144
1145                         eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1146                         return;
1147                 }
1148         }
1149
1150         if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1151         {
1152                 eDebug("reached SOF");
1153                 m_skipmode_m = 0;
1154                 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1155         }
1156
1157         start = current_offset;
1158         size = max;
1159
1160         eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
1161         return;
1162 }
1163
1164 void eDVBChannel::AddUse()
1165 {
1166         if (++m_use_count > 1 && m_state == state_last_instance)
1167         {
1168                 m_state = state_ok;
1169                 m_stateChanged(this);
1170         }
1171 }
1172
1173 void eDVBChannel::ReleaseUse()
1174 {
1175         if (!--m_use_count)
1176         {
1177                 m_state = state_release;
1178                 m_stateChanged(this);
1179         }
1180         else if (m_use_count == 1)
1181         {
1182                 m_state = state_last_instance;
1183                 m_stateChanged(this);
1184         }
1185 }
1186
1187 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1188 {
1189         if (m_channel_id)
1190                 m_mgr->removeChannel(this);
1191                 
1192         if (!channelid)
1193                 return 0;
1194
1195         if (!m_frontend)
1196         {
1197                 eDebug("no frontend to tune!");
1198                 return -ENODEV;
1199         }
1200         
1201         m_channel_id = channelid;
1202         m_mgr->addChannel(channelid, this);
1203         m_state = state_tuning;
1204                         /* if tuning fails, shutdown the channel immediately. */
1205         int res;
1206         res = m_frontend->get().tune(*feparm);
1207         m_current_frontend_parameters = feparm;
1208         
1209         if (res)
1210         {
1211                 m_state = state_release;
1212                 m_stateChanged(this);
1213                 return res;
1214         }
1215         
1216         return 0;
1217 }
1218
1219 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1220 {
1221         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1222         return 0;
1223 }
1224
1225 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1226 {
1227         connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1228         return 0;
1229 }
1230
1231 RESULT eDVBChannel::getState(int &state)
1232 {
1233         state = m_state;
1234         return 0;
1235 }
1236
1237 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1238 {
1239         return -1;
1240 }
1241
1242 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1243 {
1244         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1245         
1246         if (!our_demux)
1247         {
1248                 demux = 0;
1249                 
1250                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1251                         return -1;
1252         }
1253         
1254         demux = *our_demux;
1255                 /* don't hold a reference to the decoding demux, we don't need it. */
1256                 
1257                 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1258                    the refcount is lost. thus, decoding demuxes are never allocated. 
1259                    
1260                    this poses a big problem for PiP. */
1261         if (cap & capDecode)
1262                 our_demux = 0;
1263         return 0;
1264 }
1265
1266 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1267 {
1268         frontend = 0;
1269         if (!m_frontend)
1270                 return -ENODEV;
1271         frontend = &m_frontend->get();
1272         if (frontend)
1273                 return 0;
1274         return -ENODEV;
1275 }
1276
1277 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &param)
1278 {
1279         param = m_current_frontend_parameters;
1280         return 0;
1281 }
1282
1283 RESULT eDVBChannel::playFile(const char *file)
1284 {
1285         ASSERT(!m_frontend);
1286         if (m_pvr_thread)
1287         {
1288                 m_pvr_thread->stop();
1289                 delete m_pvr_thread;
1290                 m_pvr_thread = 0;
1291         }
1292         
1293         m_tstools.openFile(file);
1294         
1295                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1296                    THEN DO A REAL FIX HERE! */
1297         
1298                 /* (this codepath needs to be improved anyway.) */
1299 #if HAVE_DVB_API_VERSION < 3
1300         m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1301 #else
1302         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1303 #endif
1304         if (m_pvr_fd_dst < 0)
1305         {
1306                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1307                 return -ENODEV;
1308         }
1309
1310         m_pvr_thread = new eDVBChannelFilePush();
1311         m_pvr_thread->enablePVRCommit(1);
1312         m_pvr_thread->setStreamMode(1);
1313         m_pvr_thread->setScatterGather(this);
1314
1315         if (m_pvr_thread->start(file, m_pvr_fd_dst))
1316         {
1317                 delete m_pvr_thread;
1318                 m_pvr_thread = 0;
1319                 eDebug("can't open PVR file %s (%m)", file);
1320                 return -ENOENT;
1321         }
1322         CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1323
1324         m_state = state_ok;
1325         m_stateChanged(this);
1326
1327         return 0;
1328 }
1329
1330 void eDVBChannel::stopFile()
1331 {
1332         if (m_pvr_thread)
1333         {
1334                 m_pvr_thread->stop();
1335                 ::close(m_pvr_fd_dst);
1336                 delete m_pvr_thread;
1337                 m_pvr_thread = 0;
1338         }
1339 }
1340
1341 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1342 {
1343         m_conn_cueSheetEvent = 0;
1344         m_cue = cuesheet;
1345         if (m_cue)
1346                 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1347 }
1348
1349 RESULT eDVBChannel::getLength(pts_t &len)
1350 {
1351         return m_tstools.calcLen(len);
1352 }
1353
1354 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1355 {
1356         if (!decoding_demux)
1357                 return -1;
1358         
1359         pts_t now;
1360         
1361         int r;
1362         
1363         if (mode == 0) /* demux */
1364         {
1365                 r = decoding_demux->getSTC(now, 0);
1366                 if (r)
1367                 {
1368                         eDebug("demux getSTC failed");
1369                         return -1;
1370                 }
1371         } else
1372                 now = pos; /* fixup supplied */
1373         
1374         off_t off = 0; /* TODO: fixme */
1375         r = m_tstools.fixupPTS(off, now);
1376         if (r)
1377         {
1378                 eDebug("fixup PTS failed");
1379                 return -1;
1380         }
1381         
1382         pos = now;
1383         
1384         return 0;
1385 }
1386
1387 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1388 {
1389                         /* when seeking, we have to ensure that all buffers are flushed.
1390                            there are basically 3 buffers:
1391                            a.) the filepush's internal buffer
1392                            b.) the PVR buffer (before demux)
1393                            c.) the ratebuffer (after demux)
1394                            
1395                            it's important to clear them in the correct order, otherwise
1396                            the ratebuffer (for example) would immediately refill from
1397                            the not-yet-flushed PVR buffer.
1398                         */
1399
1400         m_pvr_thread->pause();
1401                 /* flush internal filepush buffer */
1402         m_pvr_thread->flush();
1403                 /* HACK: flush PVR buffer */
1404         ::ioctl(m_pvr_fd_dst, 0);
1405         
1406                 /* flush ratebuffers (video, audio) */
1407         if (decoding_demux)
1408                 decoding_demux->flush();
1409
1410                 /* demux will also flush all decoder.. */
1411                 /* resume will re-query the SG */
1412         m_pvr_thread->resume();
1413 }
1414
1415 DEFINE_REF(eCueSheet);
1416
1417 eCueSheet::eCueSheet()
1418 {
1419         m_skipmode_ratio = 0;
1420 }
1421
1422 void eCueSheet::seekTo(int relative, const pts_t &pts)
1423 {
1424         m_lock.WrLock();
1425         m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1426         m_lock.Unlock();
1427         m_event(evtSeek);
1428 }
1429         
1430 void eCueSheet::clear()
1431 {
1432         m_lock.WrLock();
1433         m_spans.clear();
1434         m_lock.Unlock();
1435 }
1436
1437 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1438 {
1439         m_lock.WrLock();
1440         m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1441         m_lock.Unlock();
1442 }
1443
1444 void eCueSheet::commitSpans()
1445 {
1446         m_event(evtSpanChanged);
1447 }
1448
1449 void eCueSheet::setSkipmode(const pts_t &ratio)
1450 {
1451         m_lock.WrLock();
1452         m_skipmode_ratio = ratio;
1453         m_lock.Unlock();
1454         m_event(evtSkipmode);
1455 }
1456
1457 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1458 {
1459         m_decoding_demux = demux;
1460         m_decoder = decoder;
1461 }
1462
1463 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1464 {
1465         connection = new eConnection(this, m_event.connect(event));
1466         return 0;
1467 }