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