a6f4eec7c2fcae1413f4f08f0b2671a80038b41b
[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         m_is_pvr = !m_reference.path.empty();
573         
574         m_timeshift_enabled = m_timeshift_active = 0;
575         m_skipmode = 0;
576         
577         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
578         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
579         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
580
581         m_cuesheet_changed = 0;
582         m_cutlist_enabled = 1;
583 }
584
585 eDVBServicePlay::~eDVBServicePlay()
586 {
587 }
588
589 void eDVBServicePlay::gotNewEvent()
590 {
591 #if 0
592                 // debug only
593         ePtr<eServiceEvent> m_event_now, m_event_next;
594         getEvent(m_event_now, 0);
595         getEvent(m_event_next, 1);
596
597         if (m_event_now)
598                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
599         if (m_event_next)
600                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
601 #endif
602         m_event((iPlayableService*)this, evUpdatedEventInfo);
603 }
604
605 void eDVBServicePlay::serviceEvent(int event)
606 {
607         switch (event)
608         {
609         case eDVBServicePMTHandler::eventTuned:
610         {
611                 ePtr<iDVBDemux> m_demux;
612                 if (!m_service_handler.getDataDemux(m_demux))
613                 {
614                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
615                         int sid = ref.getParentServiceID().get();
616                         if (!sid)
617                                 sid = ref.getServiceID().get();
618                         if ( ref.getParentTransportStreamID().get() &&
619                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
620                                 m_event_handler.startOther(m_demux, sid);
621                         else
622                                 m_event_handler.start(m_demux, sid);
623                 }
624                 break;
625         }
626         case eDVBServicePMTHandler::eventTuneFailed:
627         {
628                 eDebug("DVB service failed to tune");
629                 m_event((iPlayableService*)this, evTuneFailed);
630                 break;
631         }
632         case eDVBServicePMTHandler::eventNewProgramInfo:
633         {
634                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
635                 if (m_timeshift_enabled)
636                         updateTimeshiftPids();
637                 if (!m_timeshift_active)
638                         updateDecoder();
639                 if (m_first_program_info && m_is_pvr)
640                 {
641                         m_first_program_info = 0;
642                         seekTo(0);
643                 }
644                 m_event((iPlayableService*)this, evUpdatedInfo);
645                 break;
646         }
647         case eDVBServicePMTHandler::eventEOF:
648                 m_event((iPlayableService*)this, evEOF);
649                 break;
650         case eDVBServicePMTHandler::eventSOF:
651                 m_event((iPlayableService*)this, evSOF);
652                 break;
653         }
654 }
655
656 void eDVBServicePlay::serviceEventTimeshift(int event)
657 {
658         switch (event)
659         {
660         case eDVBServicePMTHandler::eventNewProgramInfo:
661                 if (m_timeshift_active)
662                         updateDecoder();
663                 break;
664         case eDVBServicePMTHandler::eventSOF:
665                 m_event((iPlayableService*)this, evSOF);
666                 break;
667         case eDVBServicePMTHandler::eventEOF:
668                 switchToLive();
669                 break;
670         }
671 }
672
673 RESULT eDVBServicePlay::start()
674 {
675         int r;
676                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
677                    two (one for decoding, one for data source), as we must be prepared
678                    to start recording from the data demux. */
679         if (m_is_pvr)
680                 m_cue = new eCueSheet();
681
682         m_first_program_info = 1;
683         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
684         r = m_service_handler.tune(service, m_is_pvr, m_cue);
685         
686                 /* inject EIT if there is a stored one */
687         if (m_is_pvr)
688         {
689                 std::string filename = service.path;
690                 filename.erase(filename.length()-2, 2);
691                 filename+="eit";
692                 int fd = ::open( filename.c_str(), O_RDONLY );
693                 if ( fd > -1 )
694                 {
695                         __u8 buf[4096];
696                         int rd = ::read(fd, buf, 4096);
697                         ::close(fd);
698                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
699                         {
700                                 Event ev(buf);
701                                 ePtr<eServiceEvent> event = new eServiceEvent;
702                                 ePtr<eServiceEvent> empty;
703                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
704                                 m_event_handler.inject(event, 0);
705                                 m_event_handler.inject(empty, 1);
706                                 eDebug("injected");
707                         }
708                 }
709         }
710         
711         if (m_is_pvr)
712                 loadCuesheet();
713
714         m_event(this, evStart);
715         m_event((iPlayableService*)this, evSeekableStatusChanged);
716         return 0;
717 }
718
719 RESULT eDVBServicePlay::stop()
720 {
721         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
722
723         m_service_handler_timeshift.free();
724         m_service_handler.free();
725         
726         if (m_is_pvr && m_cuesheet_changed)
727                 saveCuesheet();
728         
729         return 0;
730 }
731
732 RESULT eDVBServicePlay::setTarget(int target)
733 {
734         m_is_primary = !target;
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_cue = 0;
1451         m_decoder = 0;
1452         m_decode_demux = 0;
1453                 /* free the timeshift service handler, we need the resources */
1454         m_service_handler_timeshift.free();
1455         m_timeshift_active = 0;
1456         
1457         m_event((iPlayableService*)this, evSeekableStatusChanged);
1458         
1459         updateDecoder();
1460 }
1461
1462 void eDVBServicePlay::switchToTimeshift()
1463 {
1464         if (m_timeshift_active)
1465                 return;
1466         
1467         m_decode_demux = 0;
1468         m_decoder = 0;
1469         
1470         m_timeshift_active = 1;
1471
1472         m_event((iPlayableService*)this, evSeekableStatusChanged);
1473         
1474         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1475         r.path = m_timeshift_file;
1476         
1477         m_cue = new eCueSheet();
1478         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1479         updateDecoder(); /* mainly to switch off PCR */
1480 }
1481
1482 void eDVBServicePlay::updateDecoder()
1483 {
1484         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1485         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1486
1487         eDVBServicePMTHandler::program program;
1488         if (h.getProgramInfo(program))
1489                 eDebug("getting program info failed.");
1490         else
1491         {
1492                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1493                 if (!program.videoStreams.empty())
1494                 {
1495                         eDebugNoNewLine(" (");
1496                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1497                                 i(program.videoStreams.begin()); 
1498                                 i != program.videoStreams.end(); ++i)
1499                         {
1500                                 if (vpid == -1)
1501                                         vpid = i->pid;
1502                                 if (i != program.videoStreams.begin())
1503                                         eDebugNoNewLine(", ");
1504                                 eDebugNoNewLine("%04x", i->pid);
1505                         }
1506                         eDebugNoNewLine(")");
1507                 }
1508                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1509                 if (!program.audioStreams.empty())
1510                 {
1511                         eDebugNoNewLine(" (");
1512                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1513                                 i(program.audioStreams.begin()); 
1514                                 i != program.audioStreams.end(); ++i)
1515                         {
1516                                 if (apid == -1)
1517                                 {
1518                                         apid = i->pid;
1519                                         apidtype = i->type;
1520                                 }
1521                                 if (i != program.audioStreams.begin())
1522                                         eDebugNoNewLine(", ");
1523                                 eDebugNoNewLine("%04x", i->pid);
1524                         }
1525                         eDebugNoNewLine(")");
1526                 }
1527                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1528                 pcrpid = program.pcrPid;
1529                 eDebug(", and the text pid is %04x", program.textPid);
1530                 tpid = program.textPid;
1531         }
1532
1533         if (!m_decoder)
1534         {
1535                 h.getDecodeDemux(m_decode_demux);
1536                 if (m_decode_demux)
1537                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1538                 if (m_cue)
1539                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1540         }
1541
1542         if (m_decoder)
1543         {
1544                 m_decoder->setVideoPID(vpid);
1545                 m_current_audio_stream = 0;
1546                 m_decoder->setAudioPID(apid, apidtype);
1547                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1548                         m_decoder->setSyncPCR(pcrpid);
1549                 else
1550                         m_decoder->setSyncPCR(-1);
1551                 m_decoder->setTextPID(tpid);
1552                 if (!m_is_primary)
1553                         m_decoder->setTrickmode(1);
1554                 m_decoder->start();
1555 // how we can do this better?
1556 // update cache pid when the user changed the audio track or video track
1557 // TODO handling of difference audio types.. default audio types..
1558                                 
1559                 /* don't worry about non-existing services, nor pvr services */
1560                 if (m_dvb_service && !m_is_pvr)
1561                 {
1562                         if (apidtype == eDVBAudio::aMPEG)
1563                         {
1564                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1565                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1566                         }
1567                         else
1568                         {
1569                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1570                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1571                         }
1572                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1573                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1574                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1575                 }
1576         }
1577 }
1578
1579 void eDVBServicePlay::loadCuesheet()
1580 {
1581         std::string filename = m_reference.path + ".cuts";
1582         
1583         m_cue_entries.clear();
1584
1585         FILE *f = fopen(filename.c_str(), "rb");
1586
1587         if (f)
1588         {
1589                 eDebug("loading cuts..");
1590                 while (1)
1591                 {
1592                         unsigned long long where;
1593                         unsigned int what;
1594                         
1595                         if (!fread(&where, sizeof(where), 1, f))
1596                                 break;
1597                         if (!fread(&what, sizeof(what), 1, f))
1598                                 break;
1599                         
1600 #if BYTE_ORDER == LITTLE_ENDIAN
1601                         where = bswap_64(where);
1602 #endif
1603                         what = ntohl(what);
1604                         
1605                         if (what > 2)
1606                                 break;
1607                         
1608                         m_cue_entries.insert(cueEntry(where, what));
1609                 }
1610                 fclose(f);
1611                 eDebug("%d entries", m_cue_entries.size());
1612         } else
1613                 eDebug("cutfile not found!");
1614         
1615         m_cuesheet_changed = 0;
1616         cutlistToCuesheet();
1617         m_event((iPlayableService*)this, evCuesheetChanged);
1618 }
1619
1620 void eDVBServicePlay::saveCuesheet()
1621 {
1622         std::string filename = m_reference.path + ".cuts";
1623         
1624         FILE *f = fopen(filename.c_str(), "wb");
1625
1626         if (f)
1627         {
1628                 unsigned long long where;
1629                 int what;
1630
1631                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1632                 {
1633 #if BYTE_ORDER == BIG_ENDIAN
1634                         where = i->where;
1635 #else
1636                         where = bswap_64(i->where);
1637 #endif
1638                         what = htonl(i->what);
1639                         fwrite(&where, sizeof(where), 1, f);
1640                         fwrite(&what, sizeof(what), 1, f);
1641                         
1642                 }
1643                 fclose(f);
1644         }
1645         
1646         m_cuesheet_changed = 0;
1647 }
1648
1649 void eDVBServicePlay::cutlistToCuesheet()
1650 {
1651         if (!m_cue)
1652         {
1653                 eDebug("no cue sheet");
1654                 return;
1655         }       
1656         m_cue->clear();
1657         
1658         if (!m_cutlist_enabled)
1659         {
1660                 m_cue->commitSpans();
1661                 eDebug("cutlists where disabled");
1662                 return;
1663         }
1664
1665         pts_t in = 0, out = 0, length = 0;
1666         
1667         getLength(length);
1668                 
1669         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1670         
1671         while (1)
1672         {
1673                 if (i == m_cue_entries.end())
1674                         out = length;
1675                 else {
1676                         if (i->what == 0) /* in */
1677                         {
1678                                 in = i++->where;
1679                                 continue;
1680                         } else if (i->what == 1) /* out */
1681                                 out = i++->where;
1682                         else /* mark */
1683                         {
1684                                 i++;
1685                                 continue;
1686                         }
1687                 }
1688                 
1689                 if (in != out)
1690                         m_cue->addSourceSpan(in, out);
1691                 
1692                 in = length;
1693                 
1694                 if (i == m_cue_entries.end())
1695                         break;
1696         }
1697         m_cue->commitSpans();
1698 }
1699
1700 DEFINE_REF(eDVBServicePlay)
1701
1702 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");