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