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