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