disable decoder when switching to timeshift, properly handle SOF
[vuplus_dvbapp] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/service/servicedvbrecord.h>
14 #include <lib/service/event.h>
15 #include <lib/dvb/metaparser.h>
16 #include <lib/dvb/tstools.h>
17 #include <lib/python/python.h>
18
19 #include <sys/vfs.h>
20
21 #include <byteswap.h>
22 #include <netinet/in.h>
23
24 #include <dvbsi++/event_information_section.h>
25
26 #ifndef BYTE_ORDER
27 #error no byte order defined!
28 #endif
29
30 #define TSPATH "/media/hdd"
31
32 class eStaticServiceDVBInformation: public iStaticServiceInformation
33 {
34         DECLARE_REF(eStaticServiceDVBInformation);
35 public:
36         RESULT getName(const eServiceReference &ref, std::string &name);
37         int getLength(const eServiceReference &ref);
38 };
39
40 DEFINE_REF(eStaticServiceDVBInformation);
41
42 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
43 {
44         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
45         if ( !ref.name.empty() )
46         {
47                 if (service.getParentTransportStreamID().get()) // linkage subservice
48                 {
49                         ePtr<iServiceHandler> service_center;
50                         if (!eServiceCenter::getInstance(service_center))
51                         {
52                                 eServiceReferenceDVB parent = service;
53                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
54                                 parent.setServiceID( service.getParentServiceID() );
55                                 parent.setParentTransportStreamID(eTransportStreamID(0));
56                                 parent.setParentServiceID(eServiceID(0));
57                                 parent.name="";
58                                 ePtr<iStaticServiceInformation> service_info;
59                                 if (!service_center->info(parent, service_info))
60                                 {
61                                         if (!service_info->getName(parent, name))
62                                         {
63                                                 // just show short name
64                                                 unsigned int pos = name.find("\xc2\x86");
65                                                 if ( pos != std::string::npos )
66                                                         name.erase(0, pos+2);
67                                                 pos = name.find("\xc2\x87");
68                                                 if ( pos != std::string::npos )
69                                                         name.erase(pos);
70                                                 name+=" - ";
71                                         }
72                                 }
73                         }
74                 }
75                 else
76                         name="";
77                 name += ref.name;
78                 return 0;
79         }
80         else
81                 return -1;
82 }
83
84 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
85 {
86         return -1;
87 }
88
89 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
90 {
91         DECLARE_REF(eStaticServiceDVBBouquetInformation);
92 public:
93         RESULT getName(const eServiceReference &ref, std::string &name);
94         int getLength(const eServiceReference &ref);
95 };
96
97 DEFINE_REF(eStaticServiceDVBBouquetInformation);
98
99 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
100 {
101         ePtr<iDVBChannelList> db;
102         ePtr<eDVBResourceManager> res;
103
104         int err;
105         if ((err = eDVBResourceManager::getInstance(res)) != 0)
106         {
107                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
108                 return err;
109         }
110         if ((err = res->getChannelList(db)) != 0)
111         {
112                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
113                 return err;
114         }
115
116         eBouquet *bouquet=0;
117         if ((err = db->getBouquet(ref, bouquet)) != 0)
118         {
119                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
120                 return -1;
121         }
122
123         if ( bouquet && bouquet->m_bouquet_name.length() )
124         {
125                 name = bouquet->m_bouquet_name;
126                 return 0;
127         }
128         else
129                 return -1;
130 }
131
132 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
133 {
134         return -1;
135 }
136
137 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
138 {
139         DECLARE_REF(eStaticServiceDVBPVRInformation);
140         eServiceReference m_ref;
141         eDVBMetaParser m_parser;
142 public:
143         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
144         RESULT getName(const eServiceReference &ref, std::string &name);
145         int getLength(const eServiceReference &ref);
146         
147         int getInfo(const eServiceReference &ref, int w);
148         std::string getInfoString(const eServiceReference &ref,int w);
149 };
150
151 DEFINE_REF(eStaticServiceDVBPVRInformation);
152
153 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
154 {
155         m_ref = ref;
156         m_parser.parseFile(ref.path);
157 }
158
159 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
160 {
161         ASSERT(ref == m_ref);
162         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
163         return 0;
164 }
165
166 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
167 {
168         ASSERT(ref == m_ref);
169         
170         eDVBTSTools tstools;
171         
172         if (tstools.openFile(ref.path.c_str()))
173                 return 0;
174
175         pts_t len;
176         if (tstools.calcLen(len))
177                 return 0;
178
179         return len / 90000;
180 }
181
182 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
183 {
184         switch (w)
185         {
186         case iServiceInformation::sDescription:
187                 return iServiceInformation::resIsString;
188         case iServiceInformation::sTimeCreate:
189                 if (m_parser.m_time_create)
190                         return m_parser.m_time_create;
191                 else
192                         return iServiceInformation::resNA;
193         default:
194                 return iServiceInformation::resNA;
195         }
196 }
197
198 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
199 {
200         switch (w)
201         {
202         case iServiceInformation::sDescription:
203                 return m_parser.m_description;
204         default:
205                 return "";
206         }
207 }
208
209 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
210 {
211         DECLARE_REF(eDVBPVRServiceOfflineOperations);
212         eServiceReferenceDVB m_ref;
213 public:
214         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
215         
216         RESULT deleteFromDisk(int simulate);
217         RESULT getListOfFilenames(std::list<std::string> &);
218 };
219
220 DEFINE_REF(eDVBPVRServiceOfflineOperations);
221
222 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
223 {
224 }
225
226 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
227 {
228         if (simulate)
229                 return 0;
230         else
231         {
232                 std::list<std::string> res;
233                 if (getListOfFilenames(res))
234                         return -1;
235                 
236                                 /* TODO: deferred removing.. */
237                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
238                 {
239                         eDebug("Removing %s...", i->c_str());
240                         ::unlink(i->c_str());
241                 }
242                 
243                 return 0;
244         }
245 }
246
247 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
248 {
249         res.clear();
250         res.push_back(m_ref.path);
251         res.push_back(m_ref.path + ".meta");
252         res.push_back(m_ref.path + ".ap");
253         res.push_back(m_ref.path + ".cuts");
254         res.push_back(m_ref.path + ".eit");
255         return 0;
256 }
257
258 DEFINE_REF(eServiceFactoryDVB)
259
260 eServiceFactoryDVB::eServiceFactoryDVB()
261 {
262         ePtr<eServiceCenter> sc;
263         
264         eServiceCenter::getPrivInstance(sc);
265         if (sc)
266                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
267 }
268
269 eServiceFactoryDVB::~eServiceFactoryDVB()
270 {
271         ePtr<eServiceCenter> sc;
272         
273         eServiceCenter::getPrivInstance(sc);
274         if (sc)
275                 sc->removeServiceFactory(eServiceFactoryDVB::id);
276 }
277
278 DEFINE_REF(eDVBServiceList);
279
280 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
281 {
282 }
283
284 eDVBServiceList::~eDVBServiceList()
285 {
286 }
287
288 RESULT eDVBServiceList::startQuery()
289 {
290         ePtr<iDVBChannelList> db;
291         ePtr<eDVBResourceManager> res;
292         
293         int err;
294         if ((err = eDVBResourceManager::getInstance(res)) != 0)
295         {
296                 eDebug("no resource manager");
297                 return err;
298         }
299         if ((err = res->getChannelList(db)) != 0)
300         {
301                 eDebug("no channel list");
302                 return err;
303         }
304         
305         ePtr<eDVBChannelQuery> q;
306         
307         if (!m_parent.path.empty())
308         {
309                 eDVBChannelQuery::compile(q, m_parent.path);
310                 if (!q)
311                 {
312                         eDebug("compile query failed");
313                         return err;
314                 }
315         }
316         
317         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
318         {
319                 eDebug("startQuery failed");
320                 return err;
321         }
322
323         return 0;
324 }
325
326 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
327 {
328         eServiceReferenceDVB ref;
329
330         if (!m_query || !list || !PyList_Check(list))
331                 return -1;
332
333         std::list<eServiceReferenceDVB> tmplist;
334
335         while (!m_query->getNextResult(ref))
336                 tmplist.push_back(ref);
337
338         if (sorted)
339                 tmplist.sort(iListableServiceCompare(this));
340
341         for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
342                 it != tmplist.end(); ++it)
343         {
344                 PyObject *refobj = New_eServiceReference(*it);
345                 PyList_Append(list, refobj);
346                 Py_DECREF(refobj);
347         }
348         return 0;
349 }
350
351 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
352 {
353         eServiceReferenceDVB ref;
354         
355         if (!m_query)
356                 return -1;
357         
358         while (!m_query->getNextResult(ref))
359                 list.push_back(ref);
360
361         if (sorted)
362                 list.sort(iListableServiceCompare(this));
363
364         return 0;
365 }
366
367 RESULT eDVBServiceList::getNext(eServiceReference &ref)
368 {
369         if (!m_query)
370                 return -1;
371         
372         return m_query->getNextResult((eServiceReferenceDVB&)ref);
373 }
374
375 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
376 {
377         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
378 }
379
380 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
381 {
382         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
383         {
384                 ePtr<iDVBChannelList> db;
385                 ePtr<eDVBResourceManager> resm;
386
387                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
388                         return -1;
389
390                 if (db->getBouquet(m_parent, m_bouquet) != 0)
391                         return -1;
392
393                 res = this;
394                 
395                 return 0;
396         }
397         res = 0;
398         return -1;
399 }
400
401 RESULT eDVBServiceList::addService(eServiceReference &ref)
402 {
403         if (!m_bouquet)
404                 return -1;
405         return m_bouquet->addService(ref);
406 }
407
408 RESULT eDVBServiceList::removeService(eServiceReference &ref)
409 {
410         if (!m_bouquet)
411                 return -1;
412         return m_bouquet->removeService(ref);
413 }
414
415 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
416 {
417         if (!m_bouquet)
418                 return -1;
419         return m_bouquet->moveService(ref, pos);
420 }
421
422 RESULT eDVBServiceList::flushChanges()
423 {
424         if (!m_bouquet)
425                 return -1;
426         return m_bouquet->flushChanges();
427 }
428
429 RESULT eDVBServiceList::setListName(const std::string &name)
430 {
431         if (!m_bouquet)
432                 return -1;
433         return m_bouquet->setListName(name);
434 }
435
436 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
437 {
438         ePtr<eDVBService> service;
439         int r = lookupService(service, ref);
440         if (r)
441                 service = 0;
442                 // check resources...
443         ptr = new eDVBServicePlay(ref, service);
444         return 0;
445 }
446
447 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
448 {
449         if (ref.path.empty())
450         {
451                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
452                 return 0;
453         } else
454         {
455                 ptr = 0;
456                 return -1;
457         }
458 }
459
460 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
461 {
462         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
463         if (list->startQuery())
464         {
465                 ptr = 0;
466                 return -1;
467         }
468         
469         ptr = list;
470         return 0;
471 }
472
473 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
474 {
475         /* is a listable service? */
476         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
477         {
478                 if ( !ref.name.empty() )  // satellites or providers list
479                         ptr = new eStaticServiceDVBInformation;
480                 else // a dvb bouquet
481                         ptr = new eStaticServiceDVBBouquetInformation;
482         }
483         else if (!ref.path.empty()) /* do we have a PVR service? */
484                 ptr = new eStaticServiceDVBPVRInformation(ref);
485         else // normal dvb service
486         {
487                 ePtr<eDVBService> service;
488                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
489                         ptr = new eStaticServiceDVBInformation;
490                 else
491                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
492                         ptr = service;
493         }
494         return 0;
495 }
496
497 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
498 {
499         if (ref.path.empty())
500         {
501                 ptr = 0;
502                 return -1;
503         } else
504         {
505                 ptr = new eDVBPVRServiceOfflineOperations(ref);
506                 return 0;
507         }
508 }
509
510 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
511 {
512                         // TODO: handle the listing itself
513         // if (ref.... == -1) .. return "... bouquets ...";
514         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
515                         // TODO: cache
516         ePtr<iDVBChannelList> db;
517         ePtr<eDVBResourceManager> res;
518         
519         int err;
520         if ((err = eDVBResourceManager::getInstance(res)) != 0)
521         {
522                 eDebug("no resource manager");
523                 return err;
524         }
525         if ((err = res->getChannelList(db)) != 0)
526         {
527                 eDebug("no channel list");
528                 return err;
529         }
530         
531                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
532         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
533         {
534                 eDebug("getService failed!");
535                 return err;
536         }
537
538         return 0;
539 }
540
541 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
542         m_reference(ref), m_dvb_service(service), m_is_paused(0)
543 {
544         m_is_pvr = !ref.path.empty();
545         
546         m_timeshift_enabled = m_timeshift_active = 0;
547         m_skipmode = 0;
548         
549         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
550         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
551         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
552
553         m_cuesheet_changed = 0;
554         m_cutlist_enabled = 1;
555 }
556
557 eDVBServicePlay::~eDVBServicePlay()
558 {
559 }
560
561 void eDVBServicePlay::gotNewEvent()
562 {
563 #if 0
564                 // debug only
565         ePtr<eServiceEvent> m_event_now, m_event_next;
566         getEvent(m_event_now, 0);
567         getEvent(m_event_next, 1);
568
569         if (m_event_now)
570                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
571         if (m_event_next)
572                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
573 #endif
574         m_event((iPlayableService*)this, evUpdatedEventInfo);
575 }
576
577 void eDVBServicePlay::serviceEvent(int event)
578 {
579         switch (event)
580         {
581         case eDVBServicePMTHandler::eventTuned:
582         {
583                 ePtr<iDVBDemux> m_demux;
584                 if (!m_service_handler.getDataDemux(m_demux))
585                 {
586                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
587                         int sid = ref.getParentServiceID().get();
588                         if (!sid)
589                                 sid = ref.getServiceID().get();
590                         if ( ref.getParentTransportStreamID().get() &&
591                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
592                                 m_event_handler.startOther(m_demux, sid);
593                         else
594                                 m_event_handler.start(m_demux, sid);
595                 }
596                 break;
597         }
598         case eDVBServicePMTHandler::eventTuneFailed:
599         {
600                 eDebug("DVB service failed to tune");
601                 m_event((iPlayableService*)this, evTuneFailed);
602                 break;
603         }
604         case eDVBServicePMTHandler::eventNewProgramInfo:
605         {
606                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
607                 if (m_timeshift_enabled)
608                         updateTimeshiftPids();
609                 if (!m_timeshift_active)
610                         updateDecoder();
611                 if (m_first_program_info && m_is_pvr)
612                 {
613                         m_first_program_info = 0;
614                         seekTo(0);
615                 }
616                 m_event((iPlayableService*)this, evUpdatedInfo);
617                 break;
618         }
619         case eDVBServicePMTHandler::eventEOF:
620                 m_event((iPlayableService*)this, evEOF);
621                 break;
622         case eDVBServicePMTHandler::eventSOF:
623                 m_event((iPlayableService*)this, evSOF);
624                 break;
625         }
626 }
627
628 void eDVBServicePlay::serviceEventTimeshift(int event)
629 {
630         switch (event)
631         {
632         case eDVBServicePMTHandler::eventNewProgramInfo:
633                 if (m_timeshift_active)
634                         updateDecoder();
635                 break;
636         case eDVBServicePMTHandler::eventSOF:
637                 m_event((iPlayableService*)this, evSOF);
638                 break;
639         case eDVBServicePMTHandler::eventEOF:
640                 switchToLive();
641                 break;
642         }
643 }
644
645 RESULT eDVBServicePlay::start()
646 {
647         int r;
648                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
649                    two (one for decoding, one for data source), as we must be prepared
650                    to start recording from the data demux. */
651         m_cue = new eCueSheet();
652
653         m_first_program_info = 1;
654         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
655         r = m_service_handler.tune(service, m_is_pvr, m_cue);
656         
657                 /* inject EIT if there is a stored one */
658         if (m_is_pvr)
659         {
660                 std::string filename = service.path;
661                 filename.erase(filename.length()-2, 2);
662                 filename+="eit";
663                 int fd = ::open( filename.c_str(), O_RDONLY );
664                 if ( fd > -1 )
665                 {
666                         __u8 buf[4096];
667                         int rd = ::read(fd, buf, 4096);
668                         ::close(fd);
669                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
670                         {
671                                 Event ev(buf);
672                                 ePtr<eServiceEvent> event = new eServiceEvent;
673                                 ePtr<eServiceEvent> empty;
674                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
675                                 m_event_handler.inject(event, 0);
676                                 m_event_handler.inject(empty, 1);
677                                 eDebug("injected");
678                         }
679                 }
680         }
681         
682         if (m_is_pvr)
683                 loadCuesheet();
684
685         m_event(this, evStart);
686         m_event((iPlayableService*)this, evSeekableStatusChanged);
687         return 0;
688 }
689
690 RESULT eDVBServicePlay::stop()
691 {
692         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
693
694         m_service_handler_timeshift.free();
695         m_service_handler.free();
696         
697         if (m_is_pvr && m_cuesheet_changed)
698                 saveCuesheet();
699         
700         return 0;
701 }
702
703 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
704 {
705         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
706         return 0;
707 }
708
709 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
710 {
711                 /* note: we check for timeshift to be enabled,
712                    not neccessary active. if you pause when timeshift
713                    is not active, you should activate it when unpausing */
714         if ((!m_is_pvr) && (!m_timeshift_enabled))
715         {
716                 ptr = 0;
717                 return -1;
718         }
719
720         ptr = this;
721         return 0;
722 }
723
724 RESULT eDVBServicePlay::setSlowMotion(int ratio)
725 {
726         if (m_decoder)
727                 return m_decoder->setSlowMotion(ratio);
728         else
729                 return -1;
730 }
731
732 RESULT eDVBServicePlay::setFastForward(int ratio)
733 {
734         int skipmode, ffratio;
735         
736         if (ratio > 8)
737         {
738                 skipmode = ratio;
739                 ffratio = 1;
740         } else if (ratio > 0)
741         {
742                 skipmode = 0;
743                 ffratio = ratio;
744         } else if (!ratio)
745         {
746                 skipmode = 0;
747                 ffratio = 0;
748         } else // if (ratio < 0)
749         {
750                 skipmode = ratio;
751                 ffratio = 1;
752         }
753
754         if (m_skipmode != skipmode)
755         {
756                 eDebug("setting cue skipmode to %d", skipmode);
757                 if (m_cue)
758                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
759         }
760         
761         m_skipmode = skipmode;
762         
763         if (!m_decoder)
764                 return -1;
765
766         return m_decoder->setFastForward(ffratio);
767 }
768     
769 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
770 {
771         if (m_is_pvr || m_timeshift_enabled)
772         {
773                 ptr = this;
774                 return 0;
775         }
776         
777         ptr = 0;
778         return -1;
779 }
780
781         /* TODO: when timeshift is enabled but not active, this doesn't work. */
782 RESULT eDVBServicePlay::getLength(pts_t &len)
783 {
784         ePtr<iDVBPVRChannel> pvr_channel;
785         
786         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
787                 return -1;
788         
789         return pvr_channel->getLength(len);
790 }
791
792 RESULT eDVBServicePlay::pause()
793 {
794         if (!m_is_paused && m_decoder)
795         {
796                 m_is_paused = 1;
797                 return m_decoder->freeze(0);
798         } else
799                 return -1;
800 }
801
802 RESULT eDVBServicePlay::unpause()
803 {
804         if (m_is_paused && m_decoder)
805         {
806                 m_is_paused = 0;
807                 return m_decoder->unfreeze();
808         } else
809                 return -1;
810 }
811
812 RESULT eDVBServicePlay::seekTo(pts_t to)
813 {
814         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
815         
816         if (!m_decode_demux)
817                 return -1;
818
819         ePtr<iDVBPVRChannel> pvr_channel;
820         
821         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
822                 return -1;
823         
824         if (!m_cue)
825                 return -1;
826         
827         m_cue->seekTo(0, to);
828         return 0;
829 }
830
831 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
832 {
833         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
834         
835         if (!m_decode_demux)
836                 return -1;
837
838         ePtr<iDVBPVRChannel> pvr_channel;
839         
840         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
841                 return -1;
842         
843         int mode = 1;
844         
845                         /* HACK until we have skip-AP api */
846         if ((to > 0) && (to < 100))
847                 mode = 2;
848         
849         to *= direction;
850         
851         if (!m_cue)
852                 return 0;
853         
854         m_cue->seekTo(mode, to);
855         return 0;
856 }
857
858 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
859 {
860         ePtr<iDVBPVRChannel> pvr_channel;
861         
862         if (!m_decode_demux)
863                 return -1;
864         
865         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
866                 return -1;
867         
868         int r = 0;
869
870                 /* if there is a decoder, use audio or video PTS */
871         if (m_decoder)
872         {
873                 r = m_decoder->getPTS(0, pos);
874                 if (r)
875                         return r;
876         }
877         
878                 /* fixup */
879         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
880 }
881
882 RESULT eDVBServicePlay::setTrickmode(int trick)
883 {
884         if (m_decoder)
885                 m_decoder->setTrickmode(trick);
886         return 0;
887 }
888
889 RESULT eDVBServicePlay::isCurrentlySeekable()
890 {
891         return m_is_pvr || m_timeshift_active;
892 }
893
894 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
895 {
896         ptr = this;
897         return 0;
898 }
899
900 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
901 {
902         ptr = this;
903         return 0;
904 }
905
906 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
907 {
908         ptr = this;
909         return 0;
910 }
911
912 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
913 {
914         ptr = this;
915         return 0;
916 }
917
918 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
919 {
920         ptr = 0;
921         if (m_timeshift_enabled || !m_is_pvr)
922         {
923                 if (!m_timeshift_enabled)
924                 {
925                                 /* we need enough diskspace */
926                         struct statfs fs;
927                         if (statfs(TSPATH "/.", &fs) < 0)
928                         {
929                                 eDebug("statfs failed!");
930                                 return -2;
931                         }
932                 
933                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
934                         {
935                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
936                                 return -3;
937                         }
938                 }
939                 ptr = this;
940                 return 0;
941         }
942         return -1;
943 }
944
945 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
946 {
947         if (m_is_pvr)
948         {
949                 ptr = this;
950                 return 0;
951         }
952         ptr = 0;
953         return -1;
954 }
955
956 RESULT eDVBServicePlay::getName(std::string &name)
957 {
958         if (m_is_pvr)
959         {
960                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
961                 return i->getName(m_reference, name);
962         }
963         if (m_dvb_service)
964         {
965                 m_dvb_service->getName(m_reference, name);
966                 if (name.empty())
967                         name = "(...)";
968         }
969         else if (!m_reference.name.empty())
970                 eStaticServiceDVBInformation().getName(m_reference, name);
971         else
972                 name = "DVB service";
973         return 0;
974 }
975
976 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
977 {
978         return m_event_handler.getEvent(evt, nownext);
979 }
980
981 int eDVBServicePlay::getInfo(int w)
982 {
983         eDVBServicePMTHandler::program program;
984
985         if (m_service_handler.getProgramInfo(program))
986                 return -1;
987         
988         switch (w)
989         {
990         case sAspect:
991                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
992                 {
993                         ePtr<eServiceEvent> evt;
994                         if (!m_event_handler.getEvent(evt, 0))
995                         {
996                                 ePtr<eComponentData> data;
997                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
998                                 {
999                                         if ( data->getStreamContent() == 1 )
1000                                         {
1001                                                 switch(data->getComponentType())
1002                                                 {
1003                                                         // SD
1004                                                         case 1: // 4:3 SD PAL
1005                                                         case 2:
1006                                                         case 3: // 16:9 SD PAL
1007                                                         case 4: // > 16:9 PAL
1008                                                         case 5: // 4:3 SD NTSC
1009                                                         case 6: 
1010                                                         case 7: // 16:9 SD NTSC
1011                                                         case 8: // > 16:9 NTSC
1012
1013                                                         // HD
1014                                                         case 9: // 4:3 HD PAL
1015                                                         case 0xA:
1016                                                         case 0xB: // 16:9 HD PAL
1017                                                         case 0xC: // > 16:9 HD PAL
1018                                                         case 0xD: // 4:3 HD NTSC
1019                                                         case 0xE:
1020                                                         case 0xF: // 16:9 HD NTSC
1021                                                         case 0x10: // > 16:9 HD PAL
1022                                                                 return data->getComponentType();
1023                                                 }
1024                                         }
1025                                 }
1026                         }
1027                 }
1028                 return -1;
1029         case sIsCrypted: return program.isCrypted;
1030         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1031         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1032         case sPCRPID: return program.pcrPid;
1033         case sPMTPID: return program.pmtPid;
1034         case sTXTPID: return program.textPid;
1035         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1036         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1037         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1038         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1039         case sProvider: if (!m_dvb_service) return -1; return -2;
1040         default:
1041                 return -1;
1042         }
1043 }
1044
1045 std::string eDVBServicePlay::getInfoString(int w)
1046 {       
1047         switch (w)
1048         {
1049         case sProvider:
1050                 if (!m_dvb_service) return "";
1051                 return m_dvb_service->m_provider_name;
1052         default:
1053                 return "";
1054         }
1055 }
1056
1057 int eDVBServicePlay::getNumberOfTracks()
1058 {
1059         eDVBServicePMTHandler::program program;
1060         if (m_service_handler.getProgramInfo(program))
1061                 return 0;
1062         return program.audioStreams.size();
1063 }
1064
1065 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1066 {
1067         int ret = selectAudioStream(i);
1068
1069         if (m_decoder->start())
1070                 return -5;
1071
1072         return ret;
1073 }
1074
1075 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1076 {
1077         eDVBServicePMTHandler::program program;
1078
1079         if (m_service_handler.getProgramInfo(program))
1080                 return -1;
1081         
1082         if (i >= program.audioStreams.size())
1083                 return -2;
1084         
1085         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1086                 info.m_description = "MPEG";
1087         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1088                 info.m_description = "AC3";
1089         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1090                 info.m_description = "DTS";
1091         else
1092                 info.m_description = "???";
1093
1094         if (program.audioStreams[i].component_tag != -1)
1095         {
1096                 ePtr<eServiceEvent> evt;
1097                 if (!m_event_handler.getEvent(evt, 0))
1098                 {
1099                         ePtr<eComponentData> data;
1100                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1101                                 info.m_language = data->getText();
1102                 }
1103         }
1104
1105         if (info.m_language.empty())
1106                 info.m_language = program.audioStreams[i].language_code;
1107         
1108         return 0;
1109 }
1110
1111 int eDVBServicePlay::selectAudioStream(int i)
1112 {
1113         eDVBServicePMTHandler::program program;
1114
1115         if (m_service_handler.getProgramInfo(program))
1116                 return -1;
1117         
1118         if ((unsigned int)i >= program.audioStreams.size())
1119                 return -2;
1120         
1121         if (!m_decoder)
1122                 return -3;
1123         
1124         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1125                 return -4;
1126
1127         if (m_dvb_service && !m_is_pvr)
1128         {
1129                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1130                 {
1131                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1132                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1133                 }       else
1134                 {
1135                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1136                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1137                 }
1138         }
1139
1140         m_current_audio_stream = i;
1141
1142         return 0;
1143 }
1144
1145 int eDVBServicePlay::getFrontendInfo(int w)
1146 {
1147         if (m_is_pvr)
1148                 return 0;
1149         eUsePtr<iDVBChannel> channel;
1150         if(m_service_handler.getChannel(channel))
1151                 return 0;
1152         ePtr<iDVBFrontend> fe;
1153         if(channel->getFrontend(fe))
1154                 return 0;
1155         return fe->readFrontendData(w);
1156 }
1157
1158 PyObject *eDVBServicePlay::getFrontendData(bool original)
1159 {
1160         PyObject *ret=0;
1161
1162         eUsePtr<iDVBChannel> channel;
1163         if(!m_service_handler.getChannel(channel))
1164         {
1165                 ePtr<iDVBFrontend> fe;
1166                 if(!channel->getFrontend(fe))
1167                 {
1168                         ret = fe->readTransponderData(original);
1169                         if (ret)
1170                         {
1171                                 ePtr<iDVBFrontendParameters> feparm;
1172                                 channel->getCurrentFrontendParameters(feparm);
1173                                 if (feparm)
1174                                 {
1175                                         eDVBFrontendParametersSatellite osat;
1176                                         if (!feparm->getDVBS(osat))
1177                                         {
1178                                                 void PutToDict(PyObject *, const char*, long);
1179                                                 void PutToDict(PyObject *, const char*, const char*);
1180                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1181                                                 const char *tmp = "UNKNOWN";
1182                                                 switch(osat.polarisation)
1183                                                 {
1184                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1185                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1186                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1187                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1188                                                         default:break;
1189                                                 }
1190                                                 PutToDict(ret, "polarization", tmp);
1191                                         }
1192                                 }
1193                         }
1194                 }
1195         }
1196         if (!ret)
1197         {
1198                 ret = Py_None;
1199                 Py_INCREF(ret);
1200         }
1201         return ret;
1202 }
1203
1204 int eDVBServicePlay::getNumberOfSubservices()
1205 {
1206         ePtr<eServiceEvent> evt;
1207         if (!m_event_handler.getEvent(evt, 0))
1208                 return evt->getNumOfLinkageServices();
1209         return 0;
1210 }
1211
1212 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1213 {
1214         ePtr<eServiceEvent> evt;
1215         if (!m_event_handler.getEvent(evt, 0))
1216         {
1217                 if (!evt->getLinkageService(sub, m_reference, n))
1218                         return 0;
1219         }
1220         sub.type=eServiceReference::idInvalid;
1221         return -1;
1222 }
1223
1224 RESULT eDVBServicePlay::startTimeshift()
1225 {
1226         ePtr<iDVBDemux> demux;
1227         
1228         eDebug("Start timeshift!");
1229         
1230         if (m_timeshift_enabled)
1231                 return -1;
1232         
1233                 /* start recording with the data demux. */
1234         if (m_service_handler.getDataDemux(demux))
1235                 return -2;
1236
1237         demux->createTSRecorder(m_record);
1238         if (!m_record)
1239                 return -3;
1240
1241         char templ[]=TSPATH "/timeshift.XXXXXX";
1242         m_timeshift_fd = mkstemp(templ);
1243         m_timeshift_file = templ;
1244         
1245         eDebug("recording to %s", templ);
1246         
1247         if (m_timeshift_fd < 0)
1248         {
1249                 m_record = 0;
1250                 return -4;
1251         }
1252                 
1253         m_record->setTargetFD(m_timeshift_fd);
1254
1255         m_timeshift_enabled = 1;
1256         
1257         updateTimeshiftPids();
1258         m_record->start();
1259
1260         return 0;
1261 }
1262
1263 RESULT eDVBServicePlay::stopTimeshift()
1264 {
1265         if (!m_timeshift_enabled)
1266                 return -1;
1267         
1268         switchToLive();
1269         
1270         m_timeshift_enabled = 0;
1271         
1272         m_record->stop();
1273         m_record = 0;
1274         
1275         close(m_timeshift_fd);
1276         eDebug("remove timeshift file");
1277         remove(m_timeshift_file.c_str());
1278         
1279         return 0;
1280 }
1281
1282 int eDVBServicePlay::isTimeshiftActive()
1283 {
1284         return m_timeshift_enabled && m_timeshift_active;
1285 }
1286
1287 RESULT eDVBServicePlay::activateTimeshift()
1288 {
1289         if (!m_timeshift_enabled)
1290                 return -1;
1291         
1292         if (!m_timeshift_active)
1293         {
1294                 switchToTimeshift();
1295                 return 0;
1296         }
1297         
1298         return -2;
1299 }
1300
1301 PyObject *eDVBServicePlay::getCutList()
1302 {
1303         PyObject *list = PyList_New(0);
1304         
1305         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1306         {
1307                 PyObject *tuple = PyTuple_New(2);
1308                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1309                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1310                 PyList_Append(list, tuple);
1311                 Py_DECREF(tuple);
1312         }
1313         
1314         return list;
1315 }
1316
1317 void eDVBServicePlay::setCutList(PyObject *list)
1318 {
1319         if (!PyList_Check(list))
1320                 return;
1321         int size = PyList_Size(list);
1322         int i;
1323         
1324         m_cue_entries.clear();
1325         
1326         for (i=0; i<size; ++i)
1327         {
1328                 PyObject *tuple = PyList_GetItem(list, i);
1329                 if (!PyTuple_Check(tuple))
1330                 {
1331                         eDebug("non-tuple in cutlist");
1332                         continue;
1333                 }
1334                 if (PyTuple_Size(tuple) != 2)
1335                 {
1336                         eDebug("cutlist entries need to be a 2-tuple");
1337                         continue;
1338                 }
1339                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1340                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1341                 {
1342                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1343                         continue;
1344                 }
1345                 pts_t pts = PyLong_AsLongLong(ppts);
1346                 int type = PyInt_AsLong(ptype);
1347                 m_cue_entries.insert(cueEntry(pts, type));
1348                 eDebug("adding %08llx, %d", pts, type);
1349         }
1350         m_cuesheet_changed = 1;
1351         
1352         cutlistToCuesheet();
1353         m_event((iPlayableService*)this, evCuesheetChanged);
1354 }
1355
1356 void eDVBServicePlay::setCutListEnable(int enable)
1357 {
1358         m_cutlist_enabled = enable;
1359         cutlistToCuesheet();
1360 }
1361
1362 void eDVBServicePlay::updateTimeshiftPids()
1363 {
1364         if (!m_record)
1365                 return;
1366         
1367         eDVBServicePMTHandler::program program;
1368         if (m_service_handler.getProgramInfo(program))
1369                 return;
1370         else
1371         {
1372                 std::set<int> pids_to_record;
1373                 pids_to_record.insert(0); // PAT
1374                 if (program.pmtPid != -1)
1375                         pids_to_record.insert(program.pmtPid); // PMT
1376
1377                 if (program.textPid != -1)
1378                         pids_to_record.insert(program.textPid); // Videotext
1379
1380                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1381                         i(program.videoStreams.begin()); 
1382                         i != program.videoStreams.end(); ++i)
1383                         pids_to_record.insert(i->pid);
1384
1385                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1386                         i(program.audioStreams.begin()); 
1387                         i != program.audioStreams.end(); ++i)
1388                                 pids_to_record.insert(i->pid);
1389
1390                 std::set<int> new_pids, obsolete_pids;
1391                 
1392                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1393                                 m_pids_active.begin(), m_pids_active.end(),
1394                                 std::inserter(new_pids, new_pids.begin()));
1395                 
1396                 std::set_difference(
1397                                 m_pids_active.begin(), m_pids_active.end(),
1398                                 pids_to_record.begin(), pids_to_record.end(), 
1399                                 std::inserter(new_pids, new_pids.begin())
1400                                 );
1401
1402                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1403                         m_record->addPID(*i);
1404
1405                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1406                         m_record->removePID(*i);
1407         }
1408 }
1409
1410 void eDVBServicePlay::switchToLive()
1411 {
1412         if (!m_timeshift_active)
1413                 return;
1414         
1415         m_decoder = 0;
1416         m_decode_demux = 0;
1417                 /* free the timeshift service handler, we need the resources */
1418         m_service_handler_timeshift.free();
1419         m_timeshift_active = 0;
1420         
1421         m_event((iPlayableService*)this, evSeekableStatusChanged);
1422         
1423         updateDecoder();
1424 }
1425
1426 void eDVBServicePlay::switchToTimeshift()
1427 {
1428         if (m_timeshift_active)
1429                 return;
1430         
1431         m_decode_demux = 0;
1432         m_decoder = 0;
1433         
1434         m_timeshift_active = 1;
1435
1436         m_event((iPlayableService*)this, evSeekableStatusChanged);
1437         
1438         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1439         r.path = m_timeshift_file;
1440         
1441         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1442         updateDecoder(); /* mainly to switch off PCR */
1443 }
1444
1445 void eDVBServicePlay::updateDecoder()
1446 {
1447         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1448         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1449
1450         eDVBServicePMTHandler::program program;
1451         if (h.getProgramInfo(program))
1452                 eDebug("getting program info failed.");
1453         else
1454         {
1455                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1456                 if (!program.videoStreams.empty())
1457                 {
1458                         eDebugNoNewLine(" (");
1459                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1460                                 i(program.videoStreams.begin()); 
1461                                 i != program.videoStreams.end(); ++i)
1462                         {
1463                                 if (vpid == -1)
1464                                         vpid = i->pid;
1465                                 if (i != program.videoStreams.begin())
1466                                         eDebugNoNewLine(", ");
1467                                 eDebugNoNewLine("%04x", i->pid);
1468                         }
1469                         eDebugNoNewLine(")");
1470                 }
1471                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1472                 if (!program.audioStreams.empty())
1473                 {
1474                         eDebugNoNewLine(" (");
1475                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1476                                 i(program.audioStreams.begin()); 
1477                                 i != program.audioStreams.end(); ++i)
1478                         {
1479                                 if (apid == -1)
1480                                 {
1481                                         apid = i->pid;
1482                                         apidtype = i->type;
1483                                 }
1484                                 if (i != program.audioStreams.begin())
1485                                         eDebugNoNewLine(", ");
1486                                 eDebugNoNewLine("%04x", i->pid);
1487                         }
1488                         eDebugNoNewLine(")");
1489                 }
1490                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1491                 pcrpid = program.pcrPid;
1492                 eDebug(", and the text pid is %04x", program.textPid);
1493                 tpid = program.textPid;
1494         }
1495
1496         if (!m_decoder)
1497         {
1498                 h.getDecodeDemux(m_decode_demux);
1499                 if (m_decode_demux)
1500                         m_decode_demux->getMPEGDecoder(m_decoder);
1501                 if (m_cue)
1502                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1503         }
1504
1505         if (m_decoder)
1506         {
1507                 m_decoder->setVideoPID(vpid);
1508                 m_current_audio_stream = 0;
1509                 m_decoder->setAudioPID(apid, apidtype);
1510                 if (!(m_is_pvr || m_timeshift_active))
1511                         m_decoder->setSyncPCR(pcrpid);
1512                 else
1513                         m_decoder->setSyncPCR(-1);
1514                 m_decoder->setTextPID(tpid);
1515                 m_decoder->start();
1516 // how we can do this better?
1517 // update cache pid when the user changed the audio track or video track
1518 // TODO handling of difference audio types.. default audio types..
1519                                 
1520                 /* don't worry about non-existing services, nor pvr services */
1521                 if (m_dvb_service && !m_is_pvr)
1522                 {
1523                         if (apidtype == eDVBAudio::aMPEG)
1524                         {
1525                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1526                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1527                         }
1528                         else
1529                         {
1530                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1531                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1532                         }
1533                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1534                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1535                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1536                 }
1537         }
1538 }
1539
1540 void eDVBServicePlay::loadCuesheet()
1541 {
1542         std::string filename = m_reference.path + ".cuts";
1543         
1544         m_cue_entries.clear();
1545
1546         FILE *f = fopen(filename.c_str(), "rb");
1547
1548         if (f)
1549         {
1550                 eDebug("loading cuts..");
1551                 while (1)
1552                 {
1553                         unsigned long long where;
1554                         unsigned int what;
1555                         
1556                         if (!fread(&where, sizeof(where), 1, f))
1557                                 break;
1558                         if (!fread(&what, sizeof(what), 1, f))
1559                                 break;
1560                         
1561 #if BYTE_ORDER == LITTLE_ENDIAN
1562                         where = bswap_64(where);
1563 #endif
1564                         what = ntohl(what);
1565                         
1566                         if (what > 2)
1567                                 break;
1568                         
1569                         m_cue_entries.insert(cueEntry(where, what));
1570                 }
1571                 fclose(f);
1572                 eDebug("%d entries", m_cue_entries.size());
1573         } else
1574                 eDebug("cutfile not found!");
1575         
1576         m_cuesheet_changed = 0;
1577         cutlistToCuesheet();
1578         m_event((iPlayableService*)this, evCuesheetChanged);
1579 }
1580
1581 void eDVBServicePlay::saveCuesheet()
1582 {
1583         std::string filename = m_reference.path + ".cuts";
1584         
1585         FILE *f = fopen(filename.c_str(), "wb");
1586
1587         if (f)
1588         {
1589                 unsigned long long where;
1590                 int what;
1591
1592                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1593                 {
1594 #if BYTE_ORDER == BIG_ENDIAN
1595                         where = i->where;
1596 #else
1597                         where = bswap_64(i->where);
1598 #endif
1599                         what = htonl(i->what);
1600                         fwrite(&where, sizeof(where), 1, f);
1601                         fwrite(&what, sizeof(what), 1, f);
1602                         
1603                 }
1604                 fclose(f);
1605         }
1606         
1607         m_cuesheet_changed = 0;
1608 }
1609
1610 void eDVBServicePlay::cutlistToCuesheet()
1611 {
1612         if (!m_cue)
1613         {
1614                 eDebug("no cue sheet");
1615                 return;
1616         }       
1617         m_cue->clear();
1618         
1619         if (!m_cutlist_enabled)
1620         {
1621                 m_cue->commitSpans();
1622                 eDebug("cutlists where disabled");
1623                 return;
1624         }
1625
1626         pts_t in = 0, out = 0, length = 0;
1627         
1628         getLength(length);
1629                 
1630         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1631         
1632         while (1)
1633         {
1634                 if (i == m_cue_entries.end())
1635                         out = length;
1636                 else {
1637                         if (i->what == 0) /* in */
1638                         {
1639                                 in = i++->where;
1640                                 continue;
1641                         } else if (i->what == 1) /* out */
1642                                 out = i++->where;
1643                         else /* mark */
1644                         {
1645                                 i++;
1646                                 continue;
1647                         }
1648                 }
1649                 
1650                 if (in != out)
1651                         m_cue->addSourceSpan(in, out);
1652                 
1653                 in = length;
1654                 
1655                 if (i == m_cue_entries.end())
1656                         break;
1657         }
1658         m_cue->commitSpans();
1659 }
1660
1661 DEFINE_REF(eDVBServicePlay)
1662
1663 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");