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