use setTarget instead of ugly 's'
[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         m_is_pvr = !m_reference.path.empty();
573         
574         m_timeshift_enabled = m_timeshift_active = 0;
575         m_skipmode = 0;
576         
577         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
578         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
579         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
580
581         m_cuesheet_changed = 0;
582         m_cutlist_enabled = 1;
583 }
584
585 eDVBServicePlay::~eDVBServicePlay()
586 {
587 }
588
589 void eDVBServicePlay::gotNewEvent()
590 {
591 #if 0
592                 // debug only
593         ePtr<eServiceEvent> m_event_now, m_event_next;
594         getEvent(m_event_now, 0);
595         getEvent(m_event_next, 1);
596
597         if (m_event_now)
598                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
599         if (m_event_next)
600                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
601 #endif
602         m_event((iPlayableService*)this, evUpdatedEventInfo);
603 }
604
605 void eDVBServicePlay::serviceEvent(int event)
606 {
607         switch (event)
608         {
609         case eDVBServicePMTHandler::eventTuned:
610         {
611                 ePtr<iDVBDemux> m_demux;
612                 if (!m_service_handler.getDataDemux(m_demux))
613                 {
614                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
615                         int sid = ref.getParentServiceID().get();
616                         if (!sid)
617                                 sid = ref.getServiceID().get();
618                         if ( ref.getParentTransportStreamID().get() &&
619                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
620                                 m_event_handler.startOther(m_demux, sid);
621                         else
622                                 m_event_handler.start(m_demux, sid);
623                 }
624                 break;
625         }
626         case eDVBServicePMTHandler::eventTuneFailed:
627         {
628                 eDebug("DVB service failed to tune");
629                 m_event((iPlayableService*)this, evTuneFailed);
630                 break;
631         }
632         case eDVBServicePMTHandler::eventNewProgramInfo:
633         {
634                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
635                 if (m_timeshift_enabled)
636                         updateTimeshiftPids();
637                 if (!m_timeshift_active)
638                         updateDecoder();
639                 if (m_first_program_info && m_is_pvr)
640                 {
641                         m_first_program_info = 0;
642                         seekTo(0);
643                 }
644                 m_event((iPlayableService*)this, evUpdatedInfo);
645                 break;
646         }
647         case eDVBServicePMTHandler::eventEOF:
648                 m_event((iPlayableService*)this, evEOF);
649                 break;
650         case eDVBServicePMTHandler::eventSOF:
651                 m_event((iPlayableService*)this, evSOF);
652                 break;
653         }
654 }
655
656 void eDVBServicePlay::serviceEventTimeshift(int event)
657 {
658         switch (event)
659         {
660         case eDVBServicePMTHandler::eventNewProgramInfo:
661                 if (m_timeshift_active)
662                         updateDecoder();
663                 break;
664         case eDVBServicePMTHandler::eventSOF:
665                 m_event((iPlayableService*)this, evSOF);
666                 break;
667         case eDVBServicePMTHandler::eventEOF:
668                 switchToLive();
669                 break;
670         }
671 }
672
673 RESULT eDVBServicePlay::start()
674 {
675         int r;
676                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
677                    two (one for decoding, one for data source), as we must be prepared
678                    to start recording from the data demux. */
679         m_cue = new eCueSheet();
680
681         m_first_program_info = 1;
682         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
683         r = m_service_handler.tune(service, m_is_pvr, m_cue);
684         
685                 /* inject EIT if there is a stored one */
686         if (m_is_pvr)
687         {
688                 std::string filename = service.path;
689                 filename.erase(filename.length()-2, 2);
690                 filename+="eit";
691                 int fd = ::open( filename.c_str(), O_RDONLY );
692                 if ( fd > -1 )
693                 {
694                         __u8 buf[4096];
695                         int rd = ::read(fd, buf, 4096);
696                         ::close(fd);
697                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
698                         {
699                                 Event ev(buf);
700                                 ePtr<eServiceEvent> event = new eServiceEvent;
701                                 ePtr<eServiceEvent> empty;
702                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
703                                 m_event_handler.inject(event, 0);
704                                 m_event_handler.inject(empty, 1);
705                                 eDebug("injected");
706                         }
707                 }
708         }
709         
710         if (m_is_pvr)
711                 loadCuesheet();
712
713         m_event(this, evStart);
714         m_event((iPlayableService*)this, evSeekableStatusChanged);
715         return 0;
716 }
717
718 RESULT eDVBServicePlay::stop()
719 {
720         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
721
722         m_service_handler_timeshift.free();
723         m_service_handler.free();
724         
725         if (m_is_pvr && m_cuesheet_changed)
726                 saveCuesheet();
727         
728         return 0;
729 }
730
731 RESULT eDVBServicePlay::setTarget(int target)
732 {
733         m_is_primary = !target;
734         return 0;
735 }
736
737 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
738 {
739         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
740         return 0;
741 }
742
743 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
744 {
745                 /* note: we check for timeshift to be enabled,
746                    not neccessary active. if you pause when timeshift
747                    is not active, you should activate it when unpausing */
748         if ((!m_is_pvr) && (!m_timeshift_enabled))
749         {
750                 ptr = 0;
751                 return -1;
752         }
753
754         ptr = this;
755         return 0;
756 }
757
758 RESULT eDVBServicePlay::setSlowMotion(int ratio)
759 {
760         if (m_decoder)
761                 return m_decoder->setSlowMotion(ratio);
762         else
763                 return -1;
764 }
765
766 RESULT eDVBServicePlay::setFastForward(int ratio)
767 {
768         int skipmode, ffratio;
769         
770         if (ratio > 8)
771         {
772                 skipmode = ratio;
773                 ffratio = 1;
774         } else if (ratio > 0)
775         {
776                 skipmode = 0;
777                 ffratio = ratio;
778         } else if (!ratio)
779         {
780                 skipmode = 0;
781                 ffratio = 0;
782         } else // if (ratio < 0)
783         {
784                 skipmode = ratio;
785                 ffratio = 1;
786         }
787
788         if (m_skipmode != skipmode)
789         {
790                 eDebug("setting cue skipmode to %d", skipmode);
791                 if (m_cue)
792                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
793         }
794         
795         m_skipmode = skipmode;
796         
797         if (!m_decoder)
798                 return -1;
799
800         return m_decoder->setFastForward(ffratio);
801 }
802     
803 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
804 {
805         if (m_is_pvr || m_timeshift_enabled)
806         {
807                 ptr = this;
808                 return 0;
809         }
810         
811         ptr = 0;
812         return -1;
813 }
814
815         /* TODO: when timeshift is enabled but not active, this doesn't work. */
816 RESULT eDVBServicePlay::getLength(pts_t &len)
817 {
818         ePtr<iDVBPVRChannel> pvr_channel;
819         
820         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
821                 return -1;
822         
823         return pvr_channel->getLength(len);
824 }
825
826 RESULT eDVBServicePlay::pause()
827 {
828         if (!m_is_paused && m_decoder)
829         {
830                 m_is_paused = 1;
831                 return m_decoder->freeze(0);
832         } else
833                 return -1;
834 }
835
836 RESULT eDVBServicePlay::unpause()
837 {
838         if (m_is_paused && m_decoder)
839         {
840                 m_is_paused = 0;
841                 return m_decoder->unfreeze();
842         } else
843                 return -1;
844 }
845
846 RESULT eDVBServicePlay::seekTo(pts_t to)
847 {
848         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
849         
850         if (!m_decode_demux)
851                 return -1;
852
853         ePtr<iDVBPVRChannel> pvr_channel;
854         
855         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
856                 return -1;
857         
858         if (!m_cue)
859                 return -1;
860         
861         m_cue->seekTo(0, to);
862         return 0;
863 }
864
865 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
866 {
867         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
868         
869         if (!m_decode_demux)
870                 return -1;
871
872         ePtr<iDVBPVRChannel> pvr_channel;
873         
874         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
875                 return -1;
876         
877         int mode = 1;
878         
879                         /* HACK until we have skip-AP api */
880         if ((to > 0) && (to < 100))
881                 mode = 2;
882         
883         to *= direction;
884         
885         if (!m_cue)
886                 return 0;
887         
888         m_cue->seekTo(mode, to);
889         return 0;
890 }
891
892 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
893 {
894         ePtr<iDVBPVRChannel> pvr_channel;
895         
896         if (!m_decode_demux)
897                 return -1;
898         
899         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
900                 return -1;
901         
902         int r = 0;
903
904                 /* if there is a decoder, use audio or video PTS */
905         if (m_decoder)
906         {
907                 r = m_decoder->getPTS(0, pos);
908                 if (r)
909                         return r;
910         }
911         
912                 /* fixup */
913         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
914 }
915
916 RESULT eDVBServicePlay::setTrickmode(int trick)
917 {
918         if (m_decoder)
919                 m_decoder->setTrickmode(trick);
920         return 0;
921 }
922
923 RESULT eDVBServicePlay::isCurrentlySeekable()
924 {
925         return m_is_pvr || m_timeshift_active;
926 }
927
928 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
929 {
930         ptr = this;
931         return 0;
932 }
933
934 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
935 {
936         ptr = this;
937         return 0;
938 }
939
940 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
941 {
942         ptr = this;
943         return 0;
944 }
945
946 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
947 {
948         ptr = this;
949         return 0;
950 }
951
952 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
953 {
954         ptr = 0;
955         if (m_timeshift_enabled || !m_is_pvr)
956         {
957                 if (!m_timeshift_enabled)
958                 {
959                                 /* we need enough diskspace */
960                         struct statfs fs;
961                         if (statfs(TSPATH "/.", &fs) < 0)
962                         {
963                                 eDebug("statfs failed!");
964                                 return -2;
965                         }
966                 
967                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
968                         {
969                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
970                                 return -3;
971                         }
972                 }
973                 ptr = this;
974                 return 0;
975         }
976         return -1;
977 }
978
979 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
980 {
981         if (m_is_pvr)
982         {
983                 ptr = this;
984                 return 0;
985         }
986         ptr = 0;
987         return -1;
988 }
989
990 RESULT eDVBServicePlay::getName(std::string &name)
991 {
992         if (m_is_pvr)
993         {
994                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
995                 return i->getName(m_reference, name);
996         }
997         if (m_dvb_service)
998         {
999                 m_dvb_service->getName(m_reference, name);
1000                 if (name.empty())
1001                         name = "(...)";
1002         }
1003         else if (!m_reference.name.empty())
1004                 eStaticServiceDVBInformation().getName(m_reference, name);
1005         else
1006                 name = "DVB service";
1007         return 0;
1008 }
1009
1010 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1011 {
1012         return m_event_handler.getEvent(evt, nownext);
1013 }
1014
1015 int eDVBServicePlay::getInfo(int w)
1016 {
1017         eDVBServicePMTHandler::program program;
1018
1019         if (m_service_handler.getProgramInfo(program))
1020                 return -1;
1021         
1022         switch (w)
1023         {
1024         case sAspect:
1025                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1026                 {
1027                         ePtr<eServiceEvent> evt;
1028                         if (!m_event_handler.getEvent(evt, 0))
1029                         {
1030                                 ePtr<eComponentData> data;
1031                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1032                                 {
1033                                         if ( data->getStreamContent() == 1 )
1034                                         {
1035                                                 switch(data->getComponentType())
1036                                                 {
1037                                                         // SD
1038                                                         case 1: // 4:3 SD PAL
1039                                                         case 2:
1040                                                         case 3: // 16:9 SD PAL
1041                                                         case 4: // > 16:9 PAL
1042                                                         case 5: // 4:3 SD NTSC
1043                                                         case 6: 
1044                                                         case 7: // 16:9 SD NTSC
1045                                                         case 8: // > 16:9 NTSC
1046
1047                                                         // HD
1048                                                         case 9: // 4:3 HD PAL
1049                                                         case 0xA:
1050                                                         case 0xB: // 16:9 HD PAL
1051                                                         case 0xC: // > 16:9 HD PAL
1052                                                         case 0xD: // 4:3 HD NTSC
1053                                                         case 0xE:
1054                                                         case 0xF: // 16:9 HD NTSC
1055                                                         case 0x10: // > 16:9 HD PAL
1056                                                                 return data->getComponentType();
1057                                                 }
1058                                         }
1059                                 }
1060                         }
1061                 }
1062                 return -1;
1063         case sIsCrypted: return program.isCrypted;
1064         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1065         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1066         case sPCRPID: return program.pcrPid;
1067         case sPMTPID: return program.pmtPid;
1068         case sTXTPID: return program.textPid;
1069         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1070         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1071         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1072         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1073         case sProvider: if (!m_dvb_service) return -1; return -2;
1074         default:
1075                 return -1;
1076         }
1077 }
1078
1079 std::string eDVBServicePlay::getInfoString(int w)
1080 {       
1081         switch (w)
1082         {
1083         case sProvider:
1084                 if (!m_dvb_service) return "";
1085                 return m_dvb_service->m_provider_name;
1086         default:
1087                 return "";
1088         }
1089 }
1090
1091 int eDVBServicePlay::getNumberOfTracks()
1092 {
1093         eDVBServicePMTHandler::program program;
1094         if (m_service_handler.getProgramInfo(program))
1095                 return 0;
1096         return program.audioStreams.size();
1097 }
1098
1099 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1100 {
1101         int ret = selectAudioStream(i);
1102
1103         if (m_decoder->start())
1104                 return -5;
1105
1106         return ret;
1107 }
1108
1109 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1110 {
1111         eDVBServicePMTHandler::program program;
1112
1113         if (m_service_handler.getProgramInfo(program))
1114                 return -1;
1115         
1116         if (i >= program.audioStreams.size())
1117                 return -2;
1118         
1119         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1120                 info.m_description = "MPEG";
1121         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1122                 info.m_description = "AC3";
1123         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1124                 info.m_description = "DTS";
1125         else
1126                 info.m_description = "???";
1127
1128         if (program.audioStreams[i].component_tag != -1)
1129         {
1130                 ePtr<eServiceEvent> evt;
1131                 if (!m_event_handler.getEvent(evt, 0))
1132                 {
1133                         ePtr<eComponentData> data;
1134                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1135                                 info.m_language = data->getText();
1136                 }
1137         }
1138
1139         if (info.m_language.empty())
1140                 info.m_language = program.audioStreams[i].language_code;
1141         
1142         return 0;
1143 }
1144
1145 int eDVBServicePlay::selectAudioStream(int i)
1146 {
1147         eDVBServicePMTHandler::program program;
1148
1149         if (m_service_handler.getProgramInfo(program))
1150                 return -1;
1151         
1152         if ((unsigned int)i >= program.audioStreams.size())
1153                 return -2;
1154         
1155         if (!m_decoder)
1156                 return -3;
1157         
1158         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1159                 return -4;
1160
1161         if (m_dvb_service && !m_is_pvr)
1162         {
1163                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1164                 {
1165                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1166                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1167                 }       else
1168                 {
1169                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1170                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1171                 }
1172         }
1173
1174         m_current_audio_stream = i;
1175
1176         return 0;
1177 }
1178
1179 int eDVBServicePlay::getFrontendInfo(int w)
1180 {
1181         if (m_is_pvr)
1182                 return 0;
1183         eUsePtr<iDVBChannel> channel;
1184         if(m_service_handler.getChannel(channel))
1185                 return 0;
1186         ePtr<iDVBFrontend> fe;
1187         if(channel->getFrontend(fe))
1188                 return 0;
1189         return fe->readFrontendData(w);
1190 }
1191
1192 PyObject *eDVBServicePlay::getFrontendData(bool original)
1193 {
1194         PyObject *ret=0;
1195
1196         eUsePtr<iDVBChannel> channel;
1197         if(!m_service_handler.getChannel(channel))
1198         {
1199                 ePtr<iDVBFrontend> fe;
1200                 if(!channel->getFrontend(fe))
1201                 {
1202                         ret = fe->readTransponderData(original);
1203                         if (ret)
1204                         {
1205                                 ePtr<iDVBFrontendParameters> feparm;
1206                                 channel->getCurrentFrontendParameters(feparm);
1207                                 if (feparm)
1208                                 {
1209                                         eDVBFrontendParametersSatellite osat;
1210                                         if (!feparm->getDVBS(osat))
1211                                         {
1212                                                 void PutToDict(PyObject *, const char*, long);
1213                                                 void PutToDict(PyObject *, const char*, const char*);
1214                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1215                                                 const char *tmp = "UNKNOWN";
1216                                                 switch(osat.polarisation)
1217                                                 {
1218                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1219                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1220                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1221                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1222                                                         default:break;
1223                                                 }
1224                                                 PutToDict(ret, "polarization", tmp);
1225                                         }
1226                                 }
1227                         }
1228                 }
1229         }
1230         if (!ret)
1231         {
1232                 ret = Py_None;
1233                 Py_INCREF(ret);
1234         }
1235         return ret;
1236 }
1237
1238 int eDVBServicePlay::getNumberOfSubservices()
1239 {
1240         ePtr<eServiceEvent> evt;
1241         if (!m_event_handler.getEvent(evt, 0))
1242                 return evt->getNumOfLinkageServices();
1243         return 0;
1244 }
1245
1246 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1247 {
1248         ePtr<eServiceEvent> evt;
1249         if (!m_event_handler.getEvent(evt, 0))
1250         {
1251                 if (!evt->getLinkageService(sub, m_reference, n))
1252                         return 0;
1253         }
1254         sub.type=eServiceReference::idInvalid;
1255         return -1;
1256 }
1257
1258 RESULT eDVBServicePlay::startTimeshift()
1259 {
1260         ePtr<iDVBDemux> demux;
1261         
1262         eDebug("Start timeshift!");
1263         
1264         if (m_timeshift_enabled)
1265                 return -1;
1266         
1267                 /* start recording with the data demux. */
1268         if (m_service_handler.getDataDemux(demux))
1269                 return -2;
1270
1271         demux->createTSRecorder(m_record);
1272         if (!m_record)
1273                 return -3;
1274
1275         char templ[]=TSPATH "/timeshift.XXXXXX";
1276         m_timeshift_fd = mkstemp(templ);
1277         m_timeshift_file = templ;
1278         
1279         eDebug("recording to %s", templ);
1280         
1281         if (m_timeshift_fd < 0)
1282         {
1283                 m_record = 0;
1284                 return -4;
1285         }
1286                 
1287         m_record->setTargetFD(m_timeshift_fd);
1288
1289         m_timeshift_enabled = 1;
1290         
1291         updateTimeshiftPids();
1292         m_record->start();
1293
1294         return 0;
1295 }
1296
1297 RESULT eDVBServicePlay::stopTimeshift()
1298 {
1299         if (!m_timeshift_enabled)
1300                 return -1;
1301         
1302         switchToLive();
1303         
1304         m_timeshift_enabled = 0;
1305         
1306         m_record->stop();
1307         m_record = 0;
1308         
1309         close(m_timeshift_fd);
1310         eDebug("remove timeshift file");
1311         remove(m_timeshift_file.c_str());
1312         
1313         return 0;
1314 }
1315
1316 int eDVBServicePlay::isTimeshiftActive()
1317 {
1318         return m_timeshift_enabled && m_timeshift_active;
1319 }
1320
1321 RESULT eDVBServicePlay::activateTimeshift()
1322 {
1323         if (!m_timeshift_enabled)
1324                 return -1;
1325         
1326         if (!m_timeshift_active)
1327         {
1328                 switchToTimeshift();
1329                 return 0;
1330         }
1331         
1332         return -2;
1333 }
1334
1335 PyObject *eDVBServicePlay::getCutList()
1336 {
1337         PyObject *list = PyList_New(0);
1338         
1339         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1340         {
1341                 PyObject *tuple = PyTuple_New(2);
1342                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1343                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1344                 PyList_Append(list, tuple);
1345                 Py_DECREF(tuple);
1346         }
1347         
1348         return list;
1349 }
1350
1351 void eDVBServicePlay::setCutList(PyObject *list)
1352 {
1353         if (!PyList_Check(list))
1354                 return;
1355         int size = PyList_Size(list);
1356         int i;
1357         
1358         m_cue_entries.clear();
1359         
1360         for (i=0; i<size; ++i)
1361         {
1362                 PyObject *tuple = PyList_GetItem(list, i);
1363                 if (!PyTuple_Check(tuple))
1364                 {
1365                         eDebug("non-tuple in cutlist");
1366                         continue;
1367                 }
1368                 if (PyTuple_Size(tuple) != 2)
1369                 {
1370                         eDebug("cutlist entries need to be a 2-tuple");
1371                         continue;
1372                 }
1373                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1374                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1375                 {
1376                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1377                         continue;
1378                 }
1379                 pts_t pts = PyLong_AsLongLong(ppts);
1380                 int type = PyInt_AsLong(ptype);
1381                 m_cue_entries.insert(cueEntry(pts, type));
1382                 eDebug("adding %08llx, %d", pts, type);
1383         }
1384         m_cuesheet_changed = 1;
1385         
1386         cutlistToCuesheet();
1387         m_event((iPlayableService*)this, evCuesheetChanged);
1388 }
1389
1390 void eDVBServicePlay::setCutListEnable(int enable)
1391 {
1392         m_cutlist_enabled = enable;
1393         cutlistToCuesheet();
1394 }
1395
1396 void eDVBServicePlay::updateTimeshiftPids()
1397 {
1398         if (!m_record)
1399                 return;
1400         
1401         eDVBServicePMTHandler::program program;
1402         if (m_service_handler.getProgramInfo(program))
1403                 return;
1404         else
1405         {
1406                 std::set<int> pids_to_record;
1407                 pids_to_record.insert(0); // PAT
1408                 if (program.pmtPid != -1)
1409                         pids_to_record.insert(program.pmtPid); // PMT
1410
1411                 if (program.textPid != -1)
1412                         pids_to_record.insert(program.textPid); // Videotext
1413
1414                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1415                         i(program.videoStreams.begin()); 
1416                         i != program.videoStreams.end(); ++i)
1417                         pids_to_record.insert(i->pid);
1418
1419                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1420                         i(program.audioStreams.begin()); 
1421                         i != program.audioStreams.end(); ++i)
1422                                 pids_to_record.insert(i->pid);
1423
1424                 std::set<int> new_pids, obsolete_pids;
1425                 
1426                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1427                                 m_pids_active.begin(), m_pids_active.end(),
1428                                 std::inserter(new_pids, new_pids.begin()));
1429                 
1430                 std::set_difference(
1431                                 m_pids_active.begin(), m_pids_active.end(),
1432                                 pids_to_record.begin(), pids_to_record.end(), 
1433                                 std::inserter(new_pids, new_pids.begin())
1434                                 );
1435
1436                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1437                         m_record->addPID(*i);
1438
1439                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1440                         m_record->removePID(*i);
1441         }
1442 }
1443
1444 void eDVBServicePlay::switchToLive()
1445 {
1446         if (!m_timeshift_active)
1447                 return;
1448         
1449         m_decoder = 0;
1450         m_decode_demux = 0;
1451                 /* free the timeshift service handler, we need the resources */
1452         m_service_handler_timeshift.free();
1453         m_timeshift_active = 0;
1454         
1455         m_event((iPlayableService*)this, evSeekableStatusChanged);
1456         
1457         updateDecoder();
1458 }
1459
1460 void eDVBServicePlay::switchToTimeshift()
1461 {
1462         if (m_timeshift_active)
1463                 return;
1464         
1465         m_decode_demux = 0;
1466         m_decoder = 0;
1467         
1468         m_timeshift_active = 1;
1469
1470         m_event((iPlayableService*)this, evSeekableStatusChanged);
1471         
1472         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1473         r.path = m_timeshift_file;
1474         
1475         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1476         updateDecoder(); /* mainly to switch off PCR */
1477 }
1478
1479 void eDVBServicePlay::updateDecoder()
1480 {
1481         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1482         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1483
1484         eDVBServicePMTHandler::program program;
1485         if (h.getProgramInfo(program))
1486                 eDebug("getting program info failed.");
1487         else
1488         {
1489                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1490                 if (!program.videoStreams.empty())
1491                 {
1492                         eDebugNoNewLine(" (");
1493                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1494                                 i(program.videoStreams.begin()); 
1495                                 i != program.videoStreams.end(); ++i)
1496                         {
1497                                 if (vpid == -1)
1498                                         vpid = i->pid;
1499                                 if (i != program.videoStreams.begin())
1500                                         eDebugNoNewLine(", ");
1501                                 eDebugNoNewLine("%04x", i->pid);
1502                         }
1503                         eDebugNoNewLine(")");
1504                 }
1505                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1506                 if (!program.audioStreams.empty())
1507                 {
1508                         eDebugNoNewLine(" (");
1509                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1510                                 i(program.audioStreams.begin()); 
1511                                 i != program.audioStreams.end(); ++i)
1512                         {
1513                                 if (apid == -1)
1514                                 {
1515                                         apid = i->pid;
1516                                         apidtype = i->type;
1517                                 }
1518                                 if (i != program.audioStreams.begin())
1519                                         eDebugNoNewLine(", ");
1520                                 eDebugNoNewLine("%04x", i->pid);
1521                         }
1522                         eDebugNoNewLine(")");
1523                 }
1524                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1525                 pcrpid = program.pcrPid;
1526                 eDebug(", and the text pid is %04x", program.textPid);
1527                 tpid = program.textPid;
1528         }
1529
1530         if (!m_decoder)
1531         {
1532                 h.getDecodeDemux(m_decode_demux);
1533                 if (m_decode_demux)
1534                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1535                 if (m_cue)
1536                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1537         }
1538
1539         if (m_decoder)
1540         {
1541                 m_decoder->setVideoPID(vpid);
1542                 m_current_audio_stream = 0;
1543                 m_decoder->setAudioPID(apid, apidtype);
1544                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1545                         m_decoder->setSyncPCR(pcrpid);
1546                 else
1547                         m_decoder->setSyncPCR(-1);
1548                 m_decoder->setTextPID(tpid);
1549                 if (!m_is_primary)
1550                         m_decoder->setTrickmode(1);
1551                 m_decoder->start();
1552 // how we can do this better?
1553 // update cache pid when the user changed the audio track or video track
1554 // TODO handling of difference audio types.. default audio types..
1555                                 
1556                 /* don't worry about non-existing services, nor pvr services */
1557                 if (m_dvb_service && !m_is_pvr)
1558                 {
1559                         if (apidtype == eDVBAudio::aMPEG)
1560                         {
1561                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1562                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1563                         }
1564                         else
1565                         {
1566                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1567                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1568                         }
1569                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1570                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1571                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1572                 }
1573         }
1574 }
1575
1576 void eDVBServicePlay::loadCuesheet()
1577 {
1578         std::string filename = m_reference.path + ".cuts";
1579         
1580         m_cue_entries.clear();
1581
1582         FILE *f = fopen(filename.c_str(), "rb");
1583
1584         if (f)
1585         {
1586                 eDebug("loading cuts..");
1587                 while (1)
1588                 {
1589                         unsigned long long where;
1590                         unsigned int what;
1591                         
1592                         if (!fread(&where, sizeof(where), 1, f))
1593                                 break;
1594                         if (!fread(&what, sizeof(what), 1, f))
1595                                 break;
1596                         
1597 #if BYTE_ORDER == LITTLE_ENDIAN
1598                         where = bswap_64(where);
1599 #endif
1600                         what = ntohl(what);
1601                         
1602                         if (what > 2)
1603                                 break;
1604                         
1605                         m_cue_entries.insert(cueEntry(where, what));
1606                 }
1607                 fclose(f);
1608                 eDebug("%d entries", m_cue_entries.size());
1609         } else
1610                 eDebug("cutfile not found!");
1611         
1612         m_cuesheet_changed = 0;
1613         cutlistToCuesheet();
1614         m_event((iPlayableService*)this, evCuesheetChanged);
1615 }
1616
1617 void eDVBServicePlay::saveCuesheet()
1618 {
1619         std::string filename = m_reference.path + ".cuts";
1620         
1621         FILE *f = fopen(filename.c_str(), "wb");
1622
1623         if (f)
1624         {
1625                 unsigned long long where;
1626                 int what;
1627
1628                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1629                 {
1630 #if BYTE_ORDER == BIG_ENDIAN
1631                         where = i->where;
1632 #else
1633                         where = bswap_64(i->where);
1634 #endif
1635                         what = htonl(i->what);
1636                         fwrite(&where, sizeof(where), 1, f);
1637                         fwrite(&what, sizeof(what), 1, f);
1638                         
1639                 }
1640                 fclose(f);
1641         }
1642         
1643         m_cuesheet_changed = 0;
1644 }
1645
1646 void eDVBServicePlay::cutlistToCuesheet()
1647 {
1648         if (!m_cue)
1649         {
1650                 eDebug("no cue sheet");
1651                 return;
1652         }       
1653         m_cue->clear();
1654         
1655         if (!m_cutlist_enabled)
1656         {
1657                 m_cue->commitSpans();
1658                 eDebug("cutlists where disabled");
1659                 return;
1660         }
1661
1662         pts_t in = 0, out = 0, length = 0;
1663         
1664         getLength(length);
1665                 
1666         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1667         
1668         while (1)
1669         {
1670                 if (i == m_cue_entries.end())
1671                         out = length;
1672                 else {
1673                         if (i->what == 0) /* in */
1674                         {
1675                                 in = i++->where;
1676                                 continue;
1677                         } else if (i->what == 1) /* out */
1678                                 out = i++->where;
1679                         else /* mark */
1680                         {
1681                                 i++;
1682                                 continue;
1683                         }
1684                 }
1685                 
1686                 if (in != out)
1687                         m_cue->addSourceSpan(in, out);
1688                 
1689                 in = length;
1690                 
1691                 if (i == m_cue_entries.end())
1692                         break;
1693         }
1694         m_cue->commitSpans();
1695 }
1696
1697 DEFINE_REF(eDVBServicePlay)
1698
1699 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");