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